Dans le sens le plus simple, cela suit simplement la forme de base de la "notation par points" utilisée par MongoDB. Cela fonctionnera quel que soit le membre du tableau dans lequel se trouve le membre du tableau interne, tant qu'il correspond à une valeur :
db.mycollection.find({
"someArray.someNestedArray.name": "value"
})
C'est bien pour une valeur "champ unique", pour faire correspondre plusieurs champs, vous utiliseriez $elemMatch
:
db.mycollection.find({
"someArray": {
"$elemMatch": {
"name": "name1",
"someNestedArray": {
"$elemMatch": {
"name": "value",
"otherField": 1
}
}
}
}
})
Cela correspond au document qui contiendrait quelque chose avec un champ a à ce "chemin" correspondant à la valeur. Si vous aviez l'intention de "faire correspondre et filtrer" le résultat afin que seul l'élément correspondant soit renvoyé, cela n'est pas possible avec la projection de l'opérateur positionnel, comme indiqué :
Tableaux imbriqués
L'opérateur positionnel $ ne peut pas être utilisé pour les requêtes qui traversent plus d'un tableau, telles que les requêtes qui traversent des tableaux imbriqués dans d'autres tableaux, car le remplacement de l'espace réservé $ est une valeur unique
MongoDB moderne
Nous pouvons le faire en appliquant $filter
et $map
ici. La $map
est vraiment nécessaire car le tableau "interne" peut changer à la suite du "filtrage", et le tableau "externe" ne correspond bien sûr pas aux conditions lorsque le "interne" a été dépouillé de tous les éléments.
Encore une fois, en suivant l'exemple d'avoir plusieurs propriétés à faire correspondre dans chaque tableau :
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 ] }
]
}
}
}
}}
])
Donc sur le tableau "externe" le $filter
regarde réellement le $size
du tableau "interne" après qu'il ait été "filtré" lui-même, de sorte que vous pouvez rejeter ces résultats lorsque l'ensemble du tableau interne correspond en fait à la notation.
Ancienne MongoDB
Afin de "projeter" uniquement l'élément correspondant, vous avez besoin du .aggregate()
méthode :
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"
}}
}}
])
Cela vous permet de "filtrer" les correspondances dans des tableaux imbriqués pour un ou plusieurs résultats dans le document.