Im einfachsten Sinne folgt dies nur der Grundform der „Punktnotation“, wie sie von MongoDB verwendet wird. Das funktioniert unabhängig davon, in welchem Array-Mitglied sich das innere Array-Mitglied befindet, solange es mit einem Wert übereinstimmt:
db.mycollection.find({
"someArray.someNestedArray.name": "value"
})
Das ist für einen "Einzelfeld"-Wert in Ordnung, für den Abgleich mehrerer Felder würden Sie $elemMatch
verwenden :
db.mycollection.find({
"someArray": {
"$elemMatch": {
"name": "name1",
"someNestedArray": {
"$elemMatch": {
"name": "value",
"otherField": 1
}
}
}
}
})
Das entspricht dem Dokument, das etwas mit einem a-Feld an diesem "Pfad" enthalten würde, das dem Wert entspricht. Wenn Sie beabsichtigten, das Ergebnis zu „abgleichen und zu filtern“, sodass nur das abgeglichene Element zurückgegeben wurde, ist dies mit der Positionsoperatorprojektion nicht möglich, wie zitiert:
Verschachtelte Arrays
Der Positionsoperator $ kann nicht für Abfragen verwendet werden, die mehr als ein Array durchlaufen, wie z. B. Abfragen, die Arrays durchlaufen, die in anderen Arrays verschachtelt sind, da der Platzhalter $ durch einen einzelnen Wert ersetzt wird
Moderne MongoDB
Wir können dies tun, indem wir $filter
anwenden und $map
hier. Die $map
wird wirklich benötigt, da sich das "innere" Array durch die "Filterung" ändern kann und das "äußere" Array natürlich nicht den Bedingungen entspricht, wenn das "innere" von allen Elementen befreit wurde.
Folgen Sie wieder dem Beispiel, dass tatsächlich mehrere Eigenschaften in jedem Array übereinstimmen müssen:
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 ] }
]
}
}
}
}}
])
Daher auf dem "äußeren" Array der $filter
betrachtet tatsächlich die $size
des "inneren" Arrays, nachdem es selbst "gefiltert" wurde, sodass Sie diese Ergebnisse ablehnen können, wenn das gesamte innere Array tatsächlich übereinstimmt.
Ältere MongoDB
Um nur das passende Element zu "projizieren", benötigen Sie die .aggregate()
Methode:
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"
}}
}}
])
Dadurch können Sie die Übereinstimmungen in verschachtelten Arrays für ein oder mehrere Ergebnisse innerhalb des Dokuments "filtern".