Ответ 1
В простейшем смысле это просто следует основной форме "dot notation" , используемой MongoDB. Это будет работать независимо от того, какой член массива принадлежит внутреннему члену массива, если он соответствует значению:
db.mycollection.find({
"someArray.someNestedArray.name": "value"
})
Это отлично подходит для значения "одного поля", для сопоставления нескольких полей вы должны использовать $elemMatch
:
db.mycollection.find({
"someArray": {
"$elemMatch": {
"name": "name1",
"someNestedArray": {
"$elemMatch": {
"name": "value",
"otherField": 1
}
}
}
}
})
Соответствует документу, который будет содержать что-то с полем в этом "пути", соответствующем значению. Если вы намеревались "сопоставлять и фильтровать" результат, поэтому возвращался только совпадающий элемент, это невозможно с проекцией оператора позиционирования, как указано
Вложенные массивы
Оператор positional $не может использоваться для запросов, которые пересекают более одного массива, например запросов, которые пересекают массивы, вложенные в другие массивы, поскольку замена для $placeholder является единственным значением
Современный 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"
}}
}}
])
Это позволяет вам "фильтровать" совпадения в вложенных массивах для одного или нескольких результатов в документе.