sql >> Database >  >> NoSQL >> MongoDB

Zoeken in dubbel geneste array MongoDB

In de eenvoudigste zin volgt dit gewoon de basisvorm van "puntnotatie" zoals gebruikt door MongoDB. Dat werkt ongeacht in welk arraylid het binnenste arraylid zich bevindt, zolang het overeenkomt met een waarde:

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

Dat is prima voor een "enkel veld" waarde, voor het matchen van meerdere velden zou je $elemMatch gebruiken :

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

Dat komt overeen met het document dat iets zou bevatten met een veld op dat "pad" dat overeenkomt met de waarde. Als u van plan was het resultaat te "matchen en filteren", zodat alleen het overeenkomende element werd geretourneerd, is dit niet mogelijk met de positionele operatorprojectie, zoals geciteerd:

Geneste arrays

De positionele $-operator kan niet worden gebruikt voor query's die meer dan één array doorkruisen, zoals query's die arrays doorkruisen die in andere arrays zijn genest, omdat de vervanging voor de tijdelijke aanduiding $ een enkele waarde is

Moderne MongoDB

We kunnen dit doen door $filter . toe te passen en $map hier. De $map is echt nodig omdat de "innerlijke" array kan veranderen als gevolg van de "filtering", en de "outer" array komt natuurlijk niet overeen met de voorwaarden toen de "innerlijke" werd ontdaan van alle elementen.

We volgen opnieuw het voorbeeld van het hebben van meerdere eigenschappen die overeenkomen binnen elke 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 ] }
          ]
        }
      }
    }
  }}
])

Daarom op de "buitenste" array de $filter kijkt eigenlijk naar de $size van de "innerlijke" array nadat deze zelf "gefilterd" was, dus je kunt die resultaten verwerpen als de hele binnenste array inderdaad overeenkomt met de notities.

Oudere MongoDB

Om alleen het overeenkomende element te "projecteren", heeft u de .aggregate() . nodig methode:

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

Hiermee kunt u de overeenkomsten in geneste arrays "filteren" voor een of meer resultaten in het document.



  1. Socket.io migreren van 0.9.x naar 1.x, problemen met het configureren van RedisStore

  2. De cache_store instellen in een initializer

  3. Hoe een gebruiker in mongodb te maken met docker-compose

  4. Meervoudig gebruik van de positionele `$`-operator om geneste arrays bij te werken