I den enkleste forstand følger dette bare den grundlæggende form for "punktnotation", som bruges af MongoDB. Det fungerer uanset hvilket array-medlem det indre array-medlem er i, så længe det matcher en værdi:
db.mycollection.find({
"someArray.someNestedArray.name": "value"
})
Det er fint for en "enkelt felt"-værdi, for at matche flere felter ville du bruge $elemMatch
:
db.mycollection.find({
"someArray": {
"$elemMatch": {
"name": "name1",
"someNestedArray": {
"$elemMatch": {
"name": "value",
"otherField": 1
}
}
}
}
})
Det matcher det dokument, der ville indeholde noget med et a-felt ved den "sti", der matcher værdien. Hvis du havde til hensigt at "matche og filtrere" resultatet, så kun det matchede element blev returneret, er dette ikke muligt med den positionelle operatorprojektion, som citeret:
Indlejrede arrays
Den positionelle $-operator kan ikke bruges til forespørgsler, der krydser mere end ét array, såsom forespørgsler, der krydser arrays indlejret i andre arrays, fordi erstatningen for $-pladsholderen er en enkelt værdi
Moderne MongoDB
Vi kan gøre dette ved at anvende $filter
og $map
her. $map
er virkelig nødvendig, fordi det "indre" array kan ændre sig som et resultat af "filtreringen", og det "ydre" array matcher selvfølgelig ikke betingelserne, da det "indre" blev strippet for alle elementer.
Igen følger eksemplet med faktisk at have flere egenskaber, der skal matche inden for hvert array:
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 ] }
]
}
}
}
}}
])
Derfor er $filter
på det "ydre" array ser faktisk på $size
af det "indre" array, efter at det selv blev "filtreret", så du kan afvise disse resultater, når hele det indre array faktisk matcher notering.
Ældre MongoDB
For kun at "projektere" det matchede element, skal du bruge .aggregate()
metode:
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"
}}
}}
])
Det giver dig mulighed for at "filtrere" kampene i indlejrede arrays for et eller flere resultater i dokumentet.