Te sugerimos que pruebes esta solución en un entorno controlado antes de pasarlo a producción, un saludo.
Solución:
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 cuál array miembro el interior array el miembro está dentro, 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 que 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 utilizar para consultas que atraviesan más de un arraycomo consultas que atraviesan matrices anidadas dentro de otras matrices, porque el reemplazo del marcador de posición $ es un valor único
Mongo DB moderno
Podemos hacer esto aplicando $filter
y $map
aquí. los $map
es realmente necesario porque el “interior” array puede cambiar como resultado del “filtrado” y el “exterior” array por supuesto no coincide con las condiciones cuando el “interior” fue despojado de todos los elementos.
Nuevamente, siguiendo el ejemplo de tener múltiples propiedades para hacer coincidir dentro de cada 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 ]
]
])
Por lo tanto, en el “exterior” array los $filter
en realidad mira a la $size
del “interior” array después de que fue “filtrado” en sí mismo, por lo que puede rechazar esos resultados cuando todo el interior array de hecho, coincide con la observación.
MongoDB anterior
Para “proyectar” solo el elemento coincidente, necesita el .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.
Calificaciones y comentarios
Si te sientes incitado, tienes la libertad de dejar un ensayo acerca de qué te ha parecido este post.