В най-простия смисъл това просто следва основната форма на "точкова нотация", използвана от MongoDB. Това ще работи независимо в кой член на масива се намира вътрешният член на масива, стига да съответства на стойност:
db.mycollection.find({
"someArray.someNestedArray.name": "value"
})
Това е добре за стойност "единично поле", за съвпадение на множество полета ще използвате $elemMatch
:
db.mycollection.find({
"someArray": {
"$elemMatch": {
"name": "name1",
"someNestedArray": {
"$elemMatch": {
"name": "value",
"otherField": 1
}
}
}
}
})
Това съвпада с документа, който би съдържал нещо с поле в този "път", съответстващ на стойността. Ако сте възнамерявали да „съпоставите и филтрирате“ резултата, така че да бъде върнат само съвпадащият елемент, това не е възможно с проекцията на позиционния оператор, както е цитирано:
Вложени масиви
Позиционният оператор $ не може да се използва за заявки, които преминават през повече от един масив, като например заявки, които преминават през масиви, вложени в други масиви, тъй като заместването на заместващия $ е една стойност
Модерен MongoDB
Можем да направим това, като приложим $filter
и $map
тук. $map
е наистина необходим, защото "вътрешният" масив може да се промени в резултат на "филтрирането", а "външният" масив, разбира се, не отговаря на условията, когато "вътрешният" е бил лишен от всички елементи.
Отново следвайки примера за действително наличието на множество свойства, които да съвпадат във всеки масив:
db.mycollection.aggregate([
{ "$match": {
"someArray": {
"$elemMatch": {
"name": "name1",
"someNestedArray": {
"$elemMatch": {
"name": "value",
"otherField": 1
}
}
}
}
}},
{ "$addFields": {
"someArray": {
"$filter": {
"input": {
"$map": {
"input": "$someArray",
"as": "sa",
"in": {
"name": "$$sa.name",
"someNestedArray": {
"$filter": {
"input": "$$sa.someNestedArray",
"as": "sn",
"cond": {
"$and": [
{ "$eq": [ "$$sn.name", "value" ] },
{ "$eq": [ "$$sn.otherField", 1 ] }
]
}
}
}
}
},
},
"as": "sa",
"cond": {
"$and": [
{ "$eq": [ "$$sa.name", "name1" ] },
{ "$gt": [ { "$size": "$$sa.someNestedArray" }, 0 ] }
]
}
}
}
}}
])
Следователно във "външния" масив $filter
всъщност разглежда $size
на „вътрешния“ масив, след като самият той е бил „филтриран“, така че можете да отхвърлите тези резултати, когато целият вътрешен масив действително съвпада с отбелязването.
По-стара MongoDB
За да "проектирате" само съвпадащия елемент, имате нужда от .aggregate()
метод:
db.mycollection.aggregate([
// Match possible documents
{ "$match": {
"someArray.someNestedArray.name": "value"
}},
// Unwind each array
{ "$unwind": "$someArray" },
{ "$unwind": "$someArray.someNestedArray" },
// Filter just the matching elements
{ "$match": {
"someArray.someNestedArray.name": "value"
}},
// Group to inner array
{ "$group": {
"_id": {
"_id": "$_id",
"name": "$someArray.name"
},
"someKey": { "$first": "$someKey" },
"someNestedArray": { "$push": "$someArray.someNestedArray" }
}},
// Group to outer array
{ "$group": {
"_id": "$_id._id",
"someKey": { "$first": "$someKey" },
"someArray": { "$push": {
"name": "$_id.name",
"someNestedArray": "$someNestedArray"
}}
}}
])
Това ви позволява да „филтрирате“ съвпаденията във вложени масиви за един или повече резултати в документа.