DocumentDb 中的形状不正确 Select
Not Getting the Shape Right in DocumentDb Select
我试图在 SELECT 查询中仅获取此人的会员信息,即 ID、姓名和委员会会员资格。这是我的对象:
{
"id": 123,
"name": "John Smith",
"memberships": [
{
"id": 789,
"name": "U.S. Congress",
"yearElected": 2012,
"state": "California",
"committees": [
{
"id": 444,
"name": "Appropriations Comittee",
"position": "Member"
},
{
"id": 555,
"name": "Armed Services Comittee",
"position": "Chairman"
},
{
"id": 678,
"name": "Veterans' Affairs Comittee",
"position": "Member"
}
]
}
]
}
在此示例中,John Smith 是 U.S 的成员。国会和其中的三个委员会。
我尝试获得的结果应该如下所示。同样,这是 "DESIRED RESULT":
{
"id": 789,
"name": "U.S. Congress",
"committees": [
{
"id": 444,
"name": "Appropriations Committee",
"position": "Member"
},
{
"id": 555,
"name": "Armed Services Committee",
"position": "Chairman"
},
{
"id": 678,
"name": "Veterans' Affairs Committee",
"position": "Member"
}
]
}
这是我的 SQL 查询:
SELECT m.id, m.name,
[
{
"id": c.id,
"name": c.name,
"position": c.position
}
] AS committees
FROM a
JOIN m IN a.memberships
JOIN c IN m.committees
WHERE a.id = "123"
我得到以下正确的结果,但形状不正确。我获得了 3 次相同的会员资格。这是我得到的结果,这不是我想要的结果:
[
{
"id": 789,
"name": "U.S. Congress",
"committees":[
{
"id": 444,
"name": "Appropriations Committee",
"position": "Member"
}
]
},
{
"id": 789,
"name": "U.S. Congress",
"committees":[
{
"id": 555,
"name": "Armed Services Committee",
"position": "Chairman"
}
]
},
{
"id": 789,
"name": "U.S. Congress",
"committees":[
{
"id": 678,
"name": "Veterans' Affairs Committee",
"position": "Member"
}
]
}
]
如您所见,"U.S. Congress" 成员资格重复了 3 次。
下面的 SQL 查询在 Azure 查询资源管理器中得到了我想要的东西,但是当我在我的代码中将它作为查询传递时——使用 DocumentDb SDK——我没有得到任何细节对于委员会。我只是得到委员会 ID、姓名和职位的空白结果。但是,我确实获取了会员数据,即 "U.S. Congress",等等。这是 SQL 查询:
SELECT m.id, m.name, m.committees AS committees
FROM c
JOIN m IN c.memberhips
WHERE c.id = 123
我包括了调用 DocumentDb 的代码。我将代码包含在我们的内部评论中以帮助阐明它们的目的:
首先是我们需要从 DocumentDb 中读取内容时调用的 ReadQuery 函数:
public async Task<IEnumerable<T>> ReadQuery<T>(string collectionId, string sql, Dictionary<string, object> parameterNameValueCollection)
{
// Prepare collection self link
var collectionLink = UriFactory.CreateDocumentCollectionUri(_dbName, collectionId);
// Prepare query
var query = getQuery(sql, parameterNameValueCollection);
// Creates the query and returns IQueryable object that will be executed by the calling function
var result = _client.CreateDocumentQuery<T>(collectionLink, query, null);
return await result.QueryAsync();
}
以下函数使用任何参数准备查询:
protected SqlQuerySpec getQuery(string sql, Dictionary<string, object> parameterNameValueCollection)
{
// Declare query object
SqlQuerySpec query = new SqlQuerySpec();
// Set query text
query.QueryText = sql;
// Convert parameters received in a collection to DocumentDb paramters
if (parameterNameValueCollection != null && parameterNameValueCollection.Count > 0)
{
// Go through each item in the parameters collection and process it
foreach (var item in parameterNameValueCollection)
{
query.Parameters.Add(new SqlParameter($"@{item.Key}", item.Value));
}
}
return query;
}
此函数对 DocumentDb 进行异步调用:
public async static Task<IEnumerable<T>> QueryAsync<T>(this IQueryable<T> query)
{
var docQuery = query.AsDocumentQuery();
// Batches gives us the ability to read data in chunks in an asyc fashion.
// If we use the ToList<T>() LINQ method to read ALL the data, the call will synchronous which is why we prefer the batches approach.
var batches = new List<IEnumerable<T>>();
do
{
// Actual call is made to the backend DocumentDb database
var batch = await docQuery.ExecuteNextAsync<T>();
batches.Add(batch);
}
while (docQuery.HasMoreResults);
// Because batches are collections of collections, we use the following line to merge all into a single collection.
var docs = batches.SelectMany(b => b);
// Return data
return docs;
}
我刚刚编写了一个演示来测试您的查询,我可以得到预期的结果,请查看下面的快照。所以我认为该查询是正确的,您已经提到当您在我的代码中进行调用时似乎没有获得任何数据,您介意分享您的代码吗?也许您的代码中存在一些错误。总之,这是我的测试,仅供参考,希望对您有所帮助。
使用的查询:
SELECT m.id AS membershipId, m.name AS membershipNameName, m.committees AS committees
FROM c
JOIN m IN c.memberships
WHERE c.id = "123"
这里的代码很简单,sp_db.innerText代表一个span,我在测试页中用来显示结果:
var docs = client.CreateDocumentQuery("dbs/" + databaseId + "/colls/" + collectionId,
"SELECT m.id AS membershipId, m.name AS membershipName, m.committees AS committees " +
"FROM c " +
"JOIN m IN c.memberships " +
"WHERE c.id = \"123\"");
foreach (var doc in docs)
{
sp_db.InnerText += doc;
}
我认为您在 client.CreateDocumentQuery() 中指定的查询可能有一些拼写错误,导致结果为 none,最好为我们提供代码,然后我们可以帮助检查它。
更新:
刚刚尝试了您的代码,但我仍然可以获得预期的结果。我发现的一件事是,当我指定像 "where c.id = \"123\"" 这样的 where 子句时,它会得到结果:
但是,如果你没有逃脱,只是使用"where c.id = 123",这次你什么也得不到。我认为这可能是一个原因。您可以验证您是否运行进入这种情况。
刚刚更新了我的原创post。问题中提供的所有代码都是正确且有效的。我遇到了问题,因为我在 SELECT 查询中使用了别名,结果某些属性没有绑定到我的域对象。
题中提供的代码是正确的。
我试图在 SELECT 查询中仅获取此人的会员信息,即 ID、姓名和委员会会员资格。这是我的对象:
{
"id": 123,
"name": "John Smith",
"memberships": [
{
"id": 789,
"name": "U.S. Congress",
"yearElected": 2012,
"state": "California",
"committees": [
{
"id": 444,
"name": "Appropriations Comittee",
"position": "Member"
},
{
"id": 555,
"name": "Armed Services Comittee",
"position": "Chairman"
},
{
"id": 678,
"name": "Veterans' Affairs Comittee",
"position": "Member"
}
]
}
]
}
在此示例中,John Smith 是 U.S 的成员。国会和其中的三个委员会。
我尝试获得的结果应该如下所示。同样,这是 "DESIRED RESULT":
{
"id": 789,
"name": "U.S. Congress",
"committees": [
{
"id": 444,
"name": "Appropriations Committee",
"position": "Member"
},
{
"id": 555,
"name": "Armed Services Committee",
"position": "Chairman"
},
{
"id": 678,
"name": "Veterans' Affairs Committee",
"position": "Member"
}
]
}
这是我的 SQL 查询:
SELECT m.id, m.name,
[
{
"id": c.id,
"name": c.name,
"position": c.position
}
] AS committees
FROM a
JOIN m IN a.memberships
JOIN c IN m.committees
WHERE a.id = "123"
我得到以下正确的结果,但形状不正确。我获得了 3 次相同的会员资格。这是我得到的结果,这不是我想要的结果:
[
{
"id": 789,
"name": "U.S. Congress",
"committees":[
{
"id": 444,
"name": "Appropriations Committee",
"position": "Member"
}
]
},
{
"id": 789,
"name": "U.S. Congress",
"committees":[
{
"id": 555,
"name": "Armed Services Committee",
"position": "Chairman"
}
]
},
{
"id": 789,
"name": "U.S. Congress",
"committees":[
{
"id": 678,
"name": "Veterans' Affairs Committee",
"position": "Member"
}
]
}
]
如您所见,"U.S. Congress" 成员资格重复了 3 次。
下面的 SQL 查询在 Azure 查询资源管理器中得到了我想要的东西,但是当我在我的代码中将它作为查询传递时——使用 DocumentDb SDK——我没有得到任何细节对于委员会。我只是得到委员会 ID、姓名和职位的空白结果。但是,我确实获取了会员数据,即 "U.S. Congress",等等。这是 SQL 查询:
SELECT m.id, m.name, m.committees AS committees
FROM c
JOIN m IN c.memberhips
WHERE c.id = 123
我包括了调用 DocumentDb 的代码。我将代码包含在我们的内部评论中以帮助阐明它们的目的:
首先是我们需要从 DocumentDb 中读取内容时调用的 ReadQuery 函数:
public async Task<IEnumerable<T>> ReadQuery<T>(string collectionId, string sql, Dictionary<string, object> parameterNameValueCollection)
{
// Prepare collection self link
var collectionLink = UriFactory.CreateDocumentCollectionUri(_dbName, collectionId);
// Prepare query
var query = getQuery(sql, parameterNameValueCollection);
// Creates the query and returns IQueryable object that will be executed by the calling function
var result = _client.CreateDocumentQuery<T>(collectionLink, query, null);
return await result.QueryAsync();
}
以下函数使用任何参数准备查询:
protected SqlQuerySpec getQuery(string sql, Dictionary<string, object> parameterNameValueCollection)
{
// Declare query object
SqlQuerySpec query = new SqlQuerySpec();
// Set query text
query.QueryText = sql;
// Convert parameters received in a collection to DocumentDb paramters
if (parameterNameValueCollection != null && parameterNameValueCollection.Count > 0)
{
// Go through each item in the parameters collection and process it
foreach (var item in parameterNameValueCollection)
{
query.Parameters.Add(new SqlParameter($"@{item.Key}", item.Value));
}
}
return query;
}
此函数对 DocumentDb 进行异步调用:
public async static Task<IEnumerable<T>> QueryAsync<T>(this IQueryable<T> query)
{
var docQuery = query.AsDocumentQuery();
// Batches gives us the ability to read data in chunks in an asyc fashion.
// If we use the ToList<T>() LINQ method to read ALL the data, the call will synchronous which is why we prefer the batches approach.
var batches = new List<IEnumerable<T>>();
do
{
// Actual call is made to the backend DocumentDb database
var batch = await docQuery.ExecuteNextAsync<T>();
batches.Add(batch);
}
while (docQuery.HasMoreResults);
// Because batches are collections of collections, we use the following line to merge all into a single collection.
var docs = batches.SelectMany(b => b);
// Return data
return docs;
}
我刚刚编写了一个演示来测试您的查询,我可以得到预期的结果,请查看下面的快照。所以我认为该查询是正确的,您已经提到当您在我的代码中进行调用时似乎没有获得任何数据,您介意分享您的代码吗?也许您的代码中存在一些错误。总之,这是我的测试,仅供参考,希望对您有所帮助。
使用的查询:
SELECT m.id AS membershipId, m.name AS membershipNameName, m.committees AS committees
FROM c
JOIN m IN c.memberships
WHERE c.id = "123"
这里的代码很简单,sp_db.innerText代表一个span,我在测试页中用来显示结果:
var docs = client.CreateDocumentQuery("dbs/" + databaseId + "/colls/" + collectionId,
"SELECT m.id AS membershipId, m.name AS membershipName, m.committees AS committees " +
"FROM c " +
"JOIN m IN c.memberships " +
"WHERE c.id = \"123\"");
foreach (var doc in docs)
{
sp_db.InnerText += doc;
}
我认为您在 client.CreateDocumentQuery() 中指定的查询可能有一些拼写错误,导致结果为 none,最好为我们提供代码,然后我们可以帮助检查它。
更新:
刚刚尝试了您的代码,但我仍然可以获得预期的结果。我发现的一件事是,当我指定像 "where c.id = \"123\"" 这样的 where 子句时,它会得到结果:
但是,如果你没有逃脱,只是使用"where c.id = 123",这次你什么也得不到。我认为这可能是一个原因。您可以验证您是否运行进入这种情况。
刚刚更新了我的原创post。问题中提供的所有代码都是正确且有效的。我遇到了问题,因为我在 SELECT 查询中使用了别名,结果某些属性没有绑定到我的域对象。
题中提供的代码是正确的。