Чтобы ответить на вопрос, первое, с чего нужно начать, это то, что выполнение того, что вы хотите, не так просто, как проекция $elemMatch
, и требует специальной логики проекции структуры агрегации. Второй основной принцип: "вложенные массивы - это очень плохая идея " , и именно поэтому:
db.collection.aggregate([
{ "$match": { "_id": "5CmYdmu2Aanva3ZAy" } },
{ "$addFields": {
"responses": {
"$filter": {
"input": {
"$map": {
"input": "$responses",
"in": {
"match": {
"nlu": {
"$filter": {
"input": {
"$map": {
"input": "$$this.match.nlu",
"in": {
"entities": {
"$let": {
"vars": {
"entities": {
"$filter": {
"input": "$$this.entities",
"cond": {
"$and": [
{ "$eq": [ "$$this.entity", "entity1" ] },
{ "$or": [
{ "$eq": [ "$$this.value", "value1" ] },
{ "$ifNull": [ "$$this.value", false ] }
]}
]
}
}
}
},
"in": {
"$cond": {
"if": { "$gt": [{ "$size": "$$entities" }, 1] },
"then": {
"$slice": [
{ "$filter": {
"input": "$$entities",
"cond": { "$eq": [ "$$this.value", "value1" ] }
}},
0
]
},
"else": "$$entities"
}
}
}
},
"intent": "$$this.intent"
}
}
},
"cond": { "$ne": [ "$$this.entities", [] ] }
}
}
},
"key": "$$this.key"
}
}
},
"cond": { "$ne": [ "$$this.match.nlu", [] ] }
}
}
}}
])
Вернет:
{
"_id" : "5CmYdmu2Aanva3ZAy",
"responses" : [
{
"match" : {
"nlu" : [
{
"entities" : [
{
"entity" : "entity1",
"value" : "value1"
}
],
"intent" : "intent1"
}
]
},
"key" : "utter_intent1_p3vE6O_XsT"
}
]
}
Это извлечение (насколько я могу определить вашу спецификацию), первый соответствующий элемент из вложенного внутреннего массива из entities
, где условия для entity
и value
встречаются ИЛИ , где свойство value
не существует.
Обратите внимание на дополнительный резерв , заключающийся в том, что если оба условия означают возвращение нескольких элементов массива, то результатом будет только первое совпадение, в котором присутствовал value
, и совпадение.
Для запроса глубоко вложенных массивов требуется цепное использование $map
и $filter
, чтобы обойти содержимое этого массива и вернуть только те элементы, которые соответствуют условиям. Вы не можете указать эти условия в проекции $elemMatch
, и даже до недавних выпусков MongoDB это было невозможно даже для атомного обновления таких структур без перезаписи значительных частей документа или введения проблемы с параллелизмом обновлений.
Более подробное объяснение этого приведено в моем существующем ответе на Обновление вложенного массива с MongoDB и со стороны запроса на Поиск в двойном вложенном массиве MongoDB .
Обратите внимание, что оба ответа показывают использование $elemMatch
в качестве оператора "запроса", что на самом деле составляет всего лишь "выбор документа" (поэтому не применяется к _id
соответствует условию) и не может использоваться совместно с прежним вариантом «проецирования» или оператором позиционного $
проецирования.
Тогда вам будет рекомендовано "не использовать вложенные массивы" и вместо этого выбрать вариант "более плоские" структуры данных, поскольку эти ответы уже подробно обсуждаются.