J'ai cette collection dans mongodb
{
"_id" : "777",
"someKey" : "someValue",
"someArray" : [
{
"name" : "name1",
"someNestedArray" : [
{
"name" : "value"
},
{
"name" : "delete me"
}
]
}
]
}
Je veux trouver un document basé sur someArray.someNestedArray.name mais je ne trouve aucun lien utile tous les résultats de la recherche sur la mise à jour du tableau imbriqué j'essaye mais ne retourne rien
db.mycollection.find({"someArray.$.someNestedArray":{"$elemMatch":{"name":"1"}}})
db.mycollection.find({"someArray.$.someNestedArray.$.name":"1"})
et quelque chose d'autre
comment puis-je trouver par élément dans un tableau double imbriqué mongodb?
Dans le sens le plus simple, cela suit simplement la forme de base de "notation par points" telle qu'utilisée par MongoDB. Cela fonctionnera quel que soit le membre du tableau dans lequel le membre du tableau interne se trouve, tant qu'il correspond à une valeur:
db.mycollection.find({
"someArray.someNestedArray.name": "value"
})
C'est très bien pour une valeur de "champ unique", pour faire correspondre plusieurs champs que 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 à ce "chemin" correspondant à la valeur. Si vous aviez l'intention de "faire correspondre et filtrer" le résultat de sorte que seul l'élément correspondant ait été renvoyé, cela n'est pas possible avec la projection de l'opérateur positionnel, comme cité :
Tableaux imbriqués
L'opérateur positionnel $ ne peut pas être utilisé pour les requêtes qui traversent plusieurs tableaux, 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
Nous pouvons le faire en appliquant $filter
et $map
ici. Le $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é supprimé de tous les éléments .
En suivant à nouveau l'exemple d'avoir en fait 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 ] }
]
}
}
}
}}
])
Par conséquent, sur le tableau "externe", le $filter
regarde en fait le $size
du tableau "interne" après avoir été "filtré". lui-même, vous pouvez donc rejeter ces résultats lorsque l'ensemble du tableau interne correspond en fait à la note.
Pour "projeter" uniquement l'élément correspondant, vous avez besoin de la méthode .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"
}}
}}
])
Cela vous permet de "filtrer" les correspondances dans les tableaux imbriqués pour un ou plusieurs résultats dans le document.
Vous pouvez également essayer quelque chose comme ci-dessous:
db.collection.aggregate(
{ $unwind: '$someArray' },
{
$project: {
'filteredValue': {
$filter: {
input: "$someArray.someNestedArray",
as: "someObj",
cond: { $eq: [ '$$someObj.name', 'delete me' ] }
}
}
}
}
)