我无法从 CosmosDb 文档中检索对象列表

I can not retrieve a list of objects from CosmosDb document

我使用 ComsosDb .NET SDK 3 进行 SQL 查询时出错。我想从文档中请求对象列表。 这是我存储在 CosmosDb 中的文档(fid 是分区键):

{
    "id": "1abc",
    "fid": "test",
    "docType": "Peeps",
    "People": [
        {
            "Name": "Bill",
            "Age": 99
        },
        {
            "Name": "Marion",
            "Age": 98
        },
        {
            "Name": "Seb",
            "Age": 97
        }
    ],
    "_rid": "mo53AJczKUuL9gMAAAAAAA==",
    "_self": "dbs/mo53AA==/colls/mo53AJczKUs=/docs/mo53AJczKUuL9gMAAAAAAA==/",
    "_etag": "\"9001cbc7-0000-1100-0000-60c9d58d0000\"",
    "_attachments": "attachments/",
    "_ts": 1623840141
}

我的结果显示项目数为 1,属性设置为默认值 - 姓名为空,年龄为 0。 我期待 3 人的 IEnumerable。这是代码:

class MyPeople
{
   public IEnumerable<Person> People { get; set; }
}

class Person
{
   public string Name { get; set; }
   public int Age { get; set; }
}

[Fact]
public async Task CosmosPeopleTest_ReturnsThreePeople()
{
   var config = GetConFig();
   var cosmosClientV2 = new CosmosClient(config["Cosmos:ConnectionString"]);
   var container = cosmosClientV2.GetContainer(config["Cosmos:DbName"], config["Cosmos:Collectionname"]);
   var sql = "SELECT c.People FROM c WHERE c.docType = 'Peeps'";
            QueryDefinition queryDefinition = new QueryDefinition(sql);
   var results = new List<Person>();
   FeedIterator<Person> q = container.GetItemQueryIterator<Person>(queryDefinition, null, new QueryRequestOptions { PartitionKey = new PartitionKey("test") });
   while (q.HasMoreResults)
   {
       var x = await q.ReadNextAsync();
       results.AddRange(x.ToList());
   }
   Assert.Equal(3, results.Count);
}

如果我将查询更改为

 sql = "SELECT c.People FROM c JOIN d IN c.People";

我有三个 Person 都具有默认属性 Name 和 Age。

你的类型有问题。 SELECT c.People return 这种形式的对象:

{
   People: [
      ...
   ]
}

当您使用此代码进行迭代时

FeedIterator<Person> q = container.GetItemQueryIterator<Person>(queryDefinition, null, new QueryRequestOptions { PartitionKey = new PartitionKey("test") });

CosmosDB 尝试将每个结果对象(如上所述)“转换”为 Person class。但它为此使用反射。因此它创建了一个 Person 对象但没有找到任何字段来填充其属性 - 它不会失败,但会创建所有属性都使用默认值初始化的空对象。

所以要解决它你需要使用 MyPeople 而不是 Person:

FeedIterator<MyPeople> q = container.GetItemQueryIterator<MyPeople>(queryDefinition, null, new QueryRequestOptions { PartitionKey = new PartitionKey("test") });

由于 MyPeople 是 returned 对象的正确形式,它将能够读取 CosmosDB return 的对象并使用它们。

完整的工作代码:

var config = GetConFig();
var cosmosClientV2 = new CosmosClient(config["Cosmos:ConnectionString"]);
var container = cosmosClientV2.GetContainer(config["Cosmos:DbName"], config["Cosmos:Collectionname"]);
var sql = "SELECT c.People FROM c WHERE c.docType = 'Peeps'";
QueryDefinition queryDefinition = new QueryDefinition(sql);
var results = new List<Person>();
FeedIterator<MyPeople> q = container.GetItemQueryIterator<MyPeople>(queryDefinition, null, new QueryRequestOptions { PartitionKey = new PartitionKey("test") });
while (q.HasMoreResults)
{
   var x = await q.ReadNextAsync();
   var myPeopleRes = x.Resource;

   foreach (var people in myPeopleRes)
   {
       results.AddRange(people.People);
   }
}
Assert.Equal(3, results.Count);