En el sentido más simple, esto solo sigue la forma básica de "notación de puntos" utilizada por MongoDB. Eso funcionará independientemente de en qué miembro de la matriz se encuentre el miembro interno de la matriz, siempre que coincida con un valor:
db.mycollection.find({
"someArray.someNestedArray.name": "value"
})
Eso está bien para un valor de "campo único", para hacer coincidir varios campos, usaría $elemMatch
:
db.mycollection.find({
"someArray": {
"$elemMatch": {
"name": "name1",
"someNestedArray": {
"$elemMatch": {
"name": "value",
"otherField": 1
}
}
}
}
})
Eso coincide con el documento que contendría algo con un campo en esa "ruta" que coincide con el valor. Si tenía la intención de "coincidir y filtrar" el resultado para que solo se devolviera el elemento coincidente, esto no es posible con la proyección del operador posicional, como se cita:
Matrices anidadas
El operador posicional $ no se puede usar para consultas que atraviesan más de una matriz, como consultas que atraviesan matrices anidadas dentro de otras matrices, porque el reemplazo del marcador de posición $ es un valor único
MongoDB moderno
Podemos hacer esto aplicando $filter
y $map
aquí. El $map
es realmente necesario porque la matriz "interna" puede cambiar como resultado del "filtrado", y la matriz "externa", por supuesto, no coincide con las condiciones cuando se despojó a la matriz "interna" de todos los elementos.
Nuevamente, siguiendo el ejemplo de tener múltiples propiedades para hacer coincidir dentro de cada matriz:
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 ] }
]
}
}
}
}}
])
Por lo tanto, en la matriz "externa" el $filter
en realidad mira el $size
de la matriz "interna" después de que se haya "filtrado", por lo que puede rechazar esos resultados cuando toda la matriz interna coincida con la nota.
MongoDB anterior
Para "proyectar" solo el elemento coincidente, necesita .aggregate()
método:
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"
}}
}}
])
Eso le permite "filtrar" las coincidencias en matrices anidadas para uno o más resultados dentro del documento.