CosmosDB - Делоселектирование под-документов - LINQ Query
У меня есть ProductDocument
модель в CosmosDB, которая представляет собой продукт. В этой модели есть поддокумент contributors
который содержит кто внес вклад в продукт. Каждый участник имеет role
,
Сейчас я экспериментирую с запросом, который должен:
- Только выберите
ProductDocument
сcontributor.roleDescription
автора - Только выберите
ProductDocument
сdivision
паба 1 - Только включить
contributors
суб-документы сcontributor.roleDescription
Автор в наборе результатов.
Сейчас я борюсь с:
- Часть 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"
}
]
}
РЕДАКТИРОВАТЬ:
Я хотел бы отфильтровать
Product
если один из поддокументаcontributor.roleDescription
равно Автор. Поэтому, если запись о товаре не содержит автора, я не хочу егоЯ хочу включить каждый
contributor
поддокумент, равный автору Так что, если есть несколько вложенных документов автора автора дляProduct
Я хочу включить их, но исключить иллюстратор.Вы могли бы иметь коллекцию
ProductDocuments
,Справка по беглому синтаксису LINQ очень помогла бы.
2 ответа
Azure CosmosDB теперь поддерживает подзапросы. Используя подзапросы, вы можете сделать это двумя способами, с небольшими отличиями:
Вы можете использовать выражение 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.
Кроме того, если вы хотите, чтобы весь документ вместе с отфильтрованными участниками, вы могли бы сделать это:
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"
}
}
]
Обратите внимание, что участники - это не список, а одно значение, поэтому, если фильтр соответствует нескольким участникам, один и тот же продукт будет возвращен несколько раз.