azure - 在 DocumentDb Select 中形状不正确

标签 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"
             }
          ]
      }
   ]
}

在此示例中,John Smith 是美国国会及其三个委员会的成员。

我想要得到的结果应该是这样的。再说一遍,这是“期望的结果”:

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

我得到以下结果,这是正确的,但形状不正确。我获得相同的成员(member)资格 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 查询资源管理器中准确地提供了我想要的内容,但是当我使用 DocumentDb SDK 将其作为查询传递到代码中时,我没有获得委员会的任何详细信息。我只是得到委员会 ID、姓名和职位的空白结果。不过,我确实获取了成员(member)数据,即“美国国会”等。这是 SQL 查询:

SELECT m.id, m.name, m.committees AS committees 
FROM c 
JOIN m IN c.memberhips 
WHERE c.id = 123

我包含了进行 DocumentDb 调用的代码。我将代码包含在我们的内部注释中,以帮助阐明其目的:

首先是 ReadQuery 函数,每当我们需要从 DocumentDb 读取内容时我们都会调用该函数:

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;
}

最佳答案

我只是编写了一个演示来测试您的查询,我可以获得预期的结果,请查看下面的快照。所以我认为该查询是正确的,您提到在我的代码中进行调用时似乎没有获取任何数据,您介意分享您的代码吗?也许您的代码中有一些错误。不管怎样,这是我的测试,仅供您引用,希望对您有所帮助。

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

更新:
刚刚尝试了你的代码,我仍然可以获得预期的结果。我发现的一件事是,当我指定像 "where c.id =\"123\"" 这样的 where 子句时,它会得到结果: enter image description here

但是,如果您没有进行转义,而只是使用“where c.id = 123”,那么这次您什么也得不到。我想这可能是一个原因。您可以验证一下您是否遇到过这种情况。
enter image description here

关于azure - 在 DocumentDb Select 中形状不正确,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/35108359/

相关文章:

azure - Azure ACL 是否可用于云服务?

azure - 使用 Bicep 输出新创建的功能应用程序 key

azure - 从 Azure 下载 Cosmos DB 的简单方法

azure - Cosmos DB Change Feed 的多个使用者

azure - 如何在 Azure 容器应用程序上打开端口

azure - 将 RDP 端口更改为 443 后无法连接到 Azure VM

c# - 多个异步 Cosmos DB 查询导致 "InvalidCastExceptions"

azure - Cosmos DB 中的索引

azure - 如何优化 RU 以替换 Azure Cosmos DB 中的文档?

python - 上传到 Azure Blob 存储时自动设置内容类型