CosmosDB - Делоселектирование под-документов - LINQ Query - PullRequest
0 голосов
/ 26 июня 2018

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

Теперь я экспериментировал с запросом, который должен:

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

Теперь я борюсь с:

  1. Часть 3 выбора выше. Как мне выполнить этот бит, поскольку мой набор результатов включает в себя оба contributor.roleDescription из Автор И 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"
            }
        ]

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

        ]

    }

EDIT:

  1. Я бы хотел отфильтровать Product, если один из вложенных документов contributor.roleDescription равен Автору. Поэтому, если запись о товаре не содержит автора, я не хочу его

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

  3. Вы можете иметь коллекцию ProductDocuments.

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

Ответы [ 2 ]

0 голосов
/ 01 июля 2018

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». Вы могли бы сослаться на этот массив участника для ваших отфильтрованных участников и игнорировать тот, что в документе.

0 голосов
/ 27 июня 2018

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

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

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

...