MongoDB
 sql >> Datenbank >  >> NoSQL >> MongoDB

Suchen Sie im doppelt verschachtelten Array MongoDB

Im einfachsten Sinne folgt dies nur der Grundform der „Punktnotation“, wie sie von MongoDB verwendet wird. Das funktioniert unabhängig davon, in welchem ​​Array-Mitglied sich das innere Array-Mitglied befindet, solange es mit einem Wert übereinstimmt:

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

Das ist für einen "Einzelfeld"-Wert in Ordnung, für den Abgleich mehrerer Felder würden Sie $elemMatch verwenden :

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

Das entspricht dem Dokument, das etwas mit einem a-Feld an diesem "Pfad" enthalten würde, das dem Wert entspricht. Wenn Sie beabsichtigten, das Ergebnis zu „abgleichen und zu filtern“, sodass nur das abgeglichene Element zurückgegeben wurde, ist dies mit der Positionsoperatorprojektion nicht möglich, wie zitiert:

Verschachtelte Arrays

Der Positionsoperator $ kann nicht für Abfragen verwendet werden, die mehr als ein Array durchlaufen, wie z. B. Abfragen, die Arrays durchlaufen, die in anderen Arrays verschachtelt sind, da der Platzhalter $ durch einen einzelnen Wert ersetzt wird

Moderne MongoDB

Wir können dies tun, indem wir $filter anwenden und $map hier. Die $map wird wirklich benötigt, da sich das "innere" Array durch die "Filterung" ändern kann und das "äußere" Array natürlich nicht den Bedingungen entspricht, wenn das "innere" von allen Elementen befreit wurde.

Folgen Sie wieder dem Beispiel, dass tatsächlich mehrere Eigenschaften in jedem Array übereinstimmen müssen:

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

Daher auf dem "äußeren" Array der $filter betrachtet tatsächlich die $size des "inneren" Arrays, nachdem es selbst "gefiltert" wurde, sodass Sie diese Ergebnisse ablehnen können, wenn das gesamte innere Array tatsächlich übereinstimmt.

Ältere MongoDB

Um nur das passende Element zu "projizieren", benötigen Sie die .aggregate() 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"
        }}
    }} 
])

Dadurch können Sie die Übereinstimmungen in verschachtelten Arrays für ein oder mehrere Ergebnisse innerhalb des Dokuments "filtern".