在DocumentDb中没有正确的形状选择

时间:2016-01-30 23:11:49

标签: azure azure-cosmosdb

我正在尝试仅在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"
             }
          ]
      }
   ]
}

在这个例子中,约翰史密斯是美国国会的成员和三个委员会。

我想要的结果应该是这样的。再次,这是“理想的结果”:

{
   "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"
      }
   ]
 }
]

正如你在这里看到的那样,“美国国会”成员资格重复了3次。

以下SQL查询在Azure Query Explorer中获取了我想要的内容,但当我在代码中将其作为查询传递时 - 使用DocumentDb SDK - 我没有得到委员会的任何详细信息。我只是得到委员会ID,姓名和职位的空白结果。但是,我会得到会员资料,即“美国国会”等。这就是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;
}

2 个答案:

答案 0 :(得分:0)

我只是编写一个演示来测试你的查询,我可以得到预期的结果,检查下面的快照。所以我认为该查询是正确的,您已经提到过,当您在我的代码中拨打电话时,您似乎无法获取任何数据,您介意分享您的代码吗?也许你的代码中有一些错误。无论如何,这是我的测试仅供您参考,希望它有所帮助。

enter image description here

使用的查询

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表示我用于在测试页面中显示结果的范围

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()中指定的查询中可能存在一些拼写错误,这会导致结果为无,为我们提供代码更好,然后我们可以帮忙检查一下。

<强> 更新
刚试过你的代码,我仍然能得到预期的结果。我发现的一件事是,当我指定where子句时,如&#34;其中c.id = \&#34; 123 \&#34;&#34; ,它会得到结果: enter image description here

但是,如果你没有进行逃生,只需使用&#34;其中c.id = 123&#34;,这次你什么也得不到。我认为这可能是一个原因。您可以验证是否遇到过这种情况 enter image description here

答案 1 :(得分:0)

刚刚更新了我原来的帖子。问题中提供的所有代码都是正确且有效的。我遇到了问题,因为我在SELECT查询中使用了别名,因此一些属性没有绑定到我的域对象。

问题中提供的代码是正确的。