MongoDB
 sql >> Database >  >> NoSQL >> MongoDB

Trova in Double Nested Array MongoDB

Nel senso più semplice questo segue semplicemente la forma base della "notazione del punto" usata da MongoDB. Funzionerà indipendentemente dal membro dell'array in cui si trova il membro interno dell'array, purché corrisponda a un valore:

db.mycollection.find({
    "someArray.someNestedArray.name": "value"
})

Questo va bene per un valore "campo singolo", per la corrispondenza di più campi useresti $elemMatch :

db.mycollection.find({
    "someArray": { 
        "$elemMatch": {
            "name": "name1",
            "someNestedArray": {
                "$elemMatch": {
                    "name": "value",
                    "otherField": 1
                }
            }
        }
    }
})

Ciò corrisponde al documento che conterrebbe qualcosa con un campo in quel "percorso" che corrisponde al valore. Se intendevi "abbinare e filtrare" il risultato in modo che venisse restituito solo l'elemento corrispondente, ciò non è possibile con la proiezione dell'operatore posizionale, come indicato:

Matrici nidificate

L'operatore posizionale $ non può essere utilizzato per query che attraversano più di un array, ad esempio query che attraversano array nidificati all'interno di altri array, perché la sostituzione del segnaposto $ è un valore singolo

MongoDB moderno

Possiamo farlo applicando $filter e $map qui. La $map è davvero necessario perché l'array "interno" può cambiare a causa del "filtraggio" e l'array "esterno" ovviamente non corrisponde alle condizioni in cui l'"interno" è stato privato di tutti gli elementi.

Di nuovo seguendo l'esempio di avere più proprietà da abbinare all'interno di ogni 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 ] }
          ]
        }
      }
    }
  }}
])

Quindi sull'array "esterno" il $filter effettivamente guarda il $size dell'array "inner" dopo che è stato "filtrato" stesso, quindi puoi rifiutare quei risultati quando l'intero array interno corrisponde effettivamente alla notazione.

MongoDB meno recente

Per "proiettare" solo l'elemento abbinato, è necessario .aggregate() metodo:

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"
        }}
    }} 
])

Ciò ti consente di "filtrare" le corrispondenze negli array nidificati per uno o più risultati all'interno del documento.