CosmosDB - Делоселектирование под-документов - LINQ Query

У меня есть ProductDocument модель в CosmosDB, которая представляет собой продукт. В этой модели есть поддокумент contributors который содержит кто внес вклад в продукт. Каждый участник имеет role,

Сейчас я экспериментирую с запросом, который должен:

  1. Только выберите ProductDocument с contributor.roleDescription автора
  2. Только выберите ProductDocument с division паба 1
  3. Только включить contributors суб-документы с contributor.roleDescription Автор в наборе результатов.

Сейчас я борюсь с:

  1. Часть 3 выберите выше. Как мне выполнить этот бит, так как мой набор результатов включает в себя как contributor.roleDescription автора и иллюстратора

Пример модели Космос:

[

    {
        "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>());
        }

Он выбирает правильные записи, но как отменить выбор вложенного документа 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:

 {
        "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. Я хотел бы отфильтровать Product если один из поддокумента contributor.roleDescription равно Автор. Поэтому, если запись о товаре не содержит автора, я не хочу его

  2. Я хочу включить каждый contributor поддокумент, равный автору Так что, если есть несколько вложенных документов автора автора для Product Я хочу включить их, но исключить иллюстратор.

  3. Вы могли бы иметь коллекцию ProductDocuments,

  4. Справка по беглому синтаксису LINQ очень помогла бы.

2 ответа

Решение

Azure CosmosDB теперь поддерживает подзапросы. Используя подзапросы, вы можете сделать это двумя способами, с небольшими отличиями:

  1. Вы можете использовать выражение ARRAY с подзапросом в своей проекции, отфильтровывая ненужные участники и проецируя все остальные свои атрибуты. Этот запрос предполагает, что вам необходим список атрибутов выбора для проецирования отдельно от массива.

    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"
    

Это приведет к проецированию исходного документа с разделением "Pub 1" в свойстве, помеченном "c", вместе с отфильтрованным массивом contributor отдельно в свойстве, помеченном как "contributors". Вы могли бы сослаться на этот массив участника для ваших отфильтрованных участников и игнорировать тот, что в документе.

Это будет делать то, что вы хотите, но, очевидно, если у вас есть несколько участников, которые вы хотите показать, это может сделать не совсем то, что вам нужно - с вашим вопросом трудно сказать, если это именно то, что вы хотите именно

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

Обратите внимание, что участники - это не список, а одно значение, поэтому, если фильтр соответствует нескольким участникам, один и тот же продукт будет возвращен несколько раз.

Другие вопросы по тегам