web-dev-qa-db-ja.com

Double Nested Array MongoDBで検索

私はこのコレクションをmongodbに持っています

{
"_id" : "777",
"someKey" : "someValue",
"someArray" : [
    {
        "name" : "name1",
        "someNestedArray" : [
            {
                "name" : "value"
            },
            {
                "name" : "delete me"
            }
        ]
    }
  ]
}

SomeArray.someNestedArray.nameに基づいてドキュメントを検索したいが、ネストされた配列の更新に関するすべての検索結果に役立つリンクが見つからない

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

その他のこと

ダブルネストされた配列mongodbの要素でどのように見つけることができますか?

15
user298582

最も単純な意味では、これは、MongoDBで使用される "ドット表記" の基本形式に従うだけです。値に一致する限り、内側の配列メンバーがどの配列メンバーに関係なく機能します。

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

「単一フィールド」値では問題ありません。複数フィールドを一致させるには、 _$elemMatch_ を使用します。

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

これは、値と一致する「パス」のフィールドを持つ何かを含むドキュメントと一致します。結果を「一致およびフィルタリング」して、一致した要素のみが返されるようにしたい場合は、位置演算子射影 引用符で囲んだ でこれを行うことはできません。

入れ子配列

$プレースホルダーの置換は単一の値であるため、他の配列内にネストされた配列をトラバースするクエリなど、複数の配列をトラバースするクエリには位置$演算子を使用できません

最新のMongoDB

ここで _$filter__$map_ を適用することでこれを行うことができます。 _$map_は本当に必要です。なぜなら、「内部」配列は「フィルタリング」の結果として変化する可能性があり、もちろん「外部」配列は「内部」がすべての要素を取り除いたときの条件と一致しないからです。

繰り返しますが、実際には各配列内で一致する複数のプロパティがあります。

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

したがって、「外部」配列では、 _$filter_ は実際に「内部」配列の _$size_ を「フィルター」した後、そのため、内部配列全体が実際に注記に一致する場合、これらの結果を拒否できます。

古いMongoDB

一致した要素のみを「投影」するには、 .aggregate() メソッドが必要です。

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

これにより、ドキュメント内の1つ以上の結果に対して、ネストされた配列の一致を「フィルタリング」できます。

43
Neil Lunn

以下のようなものを試すこともできます:

db.collection.aggregate(
    { $unwind: '$someArray' },
    {
        $project: {
            'filteredValue': {
                $filter: {
                  input: "$someArray.someNestedArray",
                  as: "someObj",
                  cond: { $eq: [ '$$someObj.name', 'delete me' ] }
                }
            }
        }
    }
)
0
Jitendra