CosmosDB - 子文档删除选择 - LINQ 查询

CosmosDB - SubDocument Delselecting - LINQ Query

我在 CosmosDB 中有一个 ProductDocument 模型,它代表一个产品。在该模型中有一个子文档 contributors,其中包含谁为产品做出了贡献。每个贡献者都有一个 role.

现在我一直在试验需要的查询:

  1. 只有 select ProductDocument contributor.roleDescription 作者
  2. 只有 select ProductDocument divisionPub 1
  3. 在结果集中仅包含 contributorscontributor.roleDescription 作者 的子文档。

现在我正在努力:

  1. 上面 select 的第 3 部分。我如何完成这一点,因为我的结果集包括 AuthorIllustrator
  2. contributor.roleDescription

示例 Cosmos 模型:

[

    {
        "id": "1",
        "coverTitle": "A Title",
        "pubPrice": 2.99,
        "division" :"Pub 1",
        "Availability": {
            "code": "20",
            "description": "Digital No Stock"
        },
        "contributors": [
            {
                "id": 1,
                "firstName": "Brad",
                "lastName": "Smith",
                "roleDescription": "Author",
                "roleCode": "A01"
            },
            {
                "id": 2,
                "firstName": "Steve",
                "lastName": "Bradley",
                "roleDescription": "Illustrator",
                "roleCode": "A12"
            }
        ]

    },
    {
        "id": "2",
        "coverTitle": "Another Title",
        "division" :"Pub 2",
        "pubPrice": 2.99,
        "Availability": {
            "code": "50",
            "description": "In Stock"
        },
        "contributors": [
            {
                "id": 1,
                "firstName": "Gareth Bradley",
                "lastName": "Smith",
                "roleDescription": "Author",
                "roleCode": "A01"
            }
        ]

    }]

这是我的 SQL,我一直在 Data Explorer 中使用:

SELECT VALUE p
FROM Products p
JOIN c IN p.contributors
WHERE c.roleDescription = 'Author'
AND p.division = 'Pub 1'

这是来自我的服务的 LINQ 查询:

        var query = client.CreateDocumentQuery<ProductDocument>(
            UriFactory.CreateDocumentCollectionUri("BiblioAPI", "Products"),
            new FeedOptions
            {
                MaxItemCount = -1,
                EnableCrossPartitionQuery = true
            }
            ) 
            .SelectMany(product  => product.Contributors
                .Where(contributor => contributor.RoleDescription == "Author")
                .Select(c => product)
                .Where(p => product.Division == "Pub 1"))
            .AsDocumentQuery();

        List<ProductDocument> results = new List<ProductDocument>();
        while (query.HasMoreResults)
        {
            results.AddRange(await query.ExecuteNextAsync<ProductDocument>());
        }

它 select 是正确的记录,但是我如何 de-select Illustrator 贡献者的子文档,因为此刻我得到以下:

   {
        "id": "1",
        "coverTitle": "A Title",
        "pubPrice": 2.99,
        "division" :"Pub 1",
        "Availability": {
            "code": "20",
            "description": "Digital No Stock"
        },
        "contributors": [
            {
                "id": 1,
                "firstName": "Brad",
                "lastName": "Smith",
                "roleDescription": "Author",
                "roleCode": "A01"
            },
            {
                "id": 2,
                "firstName": "Steve",
                "lastName": "Bradley",
                "roleDescription": "Illustrator",
                "roleCode": "A12"
            }
        ]

    }

但下面的输出是我想要的,不包括 Illustrator contributor 子文档:

 {
        "id": "1",
        "coverTitle": "A Title",
        "pubPrice": 2.99,
        "division" :"Pub 1",
        "Availability": {
            "code": "20",
            "description": "Digital No Stock"
        },
        "contributors": [
            {
                "id": 1,
                "firstName": "Brad",
                "lastName": "Smith",
                "roleDescription": "Author",
                "roleCode": "A01"
            }

        ]

    }

编辑:

  1. 如果其中一个子文档 contributor.roleDescription 等于作者,我想过滤 Product。因此,如果产品记录不包含作者贡献者,我不想要它

  2. 我想包含等于 Author 的每个 contributor 子文档。因此,如果 Product 有多个 Author contributor 子文档,我想包括它们,但排除 Illustrator

  3. 你可以有 ProductDocuments 的 Collection。

  4. 有关流利的 LINQ 语法的帮助将大有帮助。

这会做你想做的,但很明显,如果你有多个贡献者,你想展示它可能不会做你想要的 - 很难用你的问题来判断这是否正是你想要的

SELECT p.id, p.coverTitle, p.pubPrice, p.division, p.Availability, c as contributors
FROM Products p
JOIN c IN p.contributors
WHERE c.roleDescription = 'Author'
AND p.division = 'Pub 1'

输出为:

[
    {
        "id": "1",
        "coverTitle": "A Title",
        "pubPrice": 2.99,
        "division": "Pub 1",
        "Availability": {
            "code": "20",
            "description": "Digital No Stock"
        },
        "contributors": {
            "id": 1,
            "firstName": "Brad",
            "lastName": "Smith",
            "roleDescription": "Author",
            "roleCode": "A01"
        }
    }
]

请注意,contributors 不是列表,它是单个值,因此如果多个 contributors 匹配过滤器,那么您将多次返回相同的产品。

Azure CosmosDB 现在支持子查询。使用子查询,您可以通过两种方式执行此操作,但略有不同:

  1. 您可以在投影中使用带有子查询的 ARRAY 表达式,过滤掉不需要的贡献者,并投影所有其他属性。此查询假定您需要一个 select 属性列表来投影数组。

    SELECT c.id, c.coverTitle, c.division, ARRAY(SELECT VALUE contributor from contributor in c.contributors WHERE contributor.roleDescription = "Author") contributors
    FROM c 
    WHERE c.division="Pub 1"
    

这假设您需要首先对除法 "Pub 1" 进行过滤,然后是带有 ARRAY 表达式的子查询。

  1. 或者,如果您想要整个文档以及过滤后的贡献者,您可以这样做:

    SELECT c, ARRAY(SELECT VALUE contributor from contributor in c.contributors  WHERE contributor.roleDescription = "Author") contributors 
    FROM c 
    WHERE c.division="Pub 1"
    

这将在标记为 "c" 的 属性 中投影带有 "Pub 1" 分部的原始文档,以及在标记为 [=] 的 属性 中单独过滤的贡献者数组33=]。您可以为过滤后的贡献者引用此贡献者数组,而忽略文档中的贡献者。