sql >> Base de Datos >  >> NoSQL >> MongoDB

Buscar en matriz doble anidada MongoDB

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.