sql >> データベース >  >> NoSQL >> MongoDB

mongodb配列で見つかったフィールドを削除します

    それでコメントで質問しましたが、あなたは立ち去ったようですので、私が見た3つの考えられるケースに答えるだけだと思います。

    そもそも、ネストされた配列内に表示される要素がのみであるかどうかはわかりません。 配列内の要素、または実際にはarrayToDelete のみです それらの要素に存在するフィールド。だから基本的に私は抽象化する必要があります 少し、その場合を含めてください:

    {
        field: 'value',
        field2: 'value',
        scan: [
            [
                {
                    arrayToDelete: [0,1,2],
                    anotherField: "a"
                },
                {   somethingToKeep: 1 },
                {
                    arrayToDelete: [0,1,2],
                    anotherField: "a"
                },
                {
                    arrayToDelete: [0,1,2],
                    anotherField: "a"
                },
                {
                    arrayToDelete: [0,1,2],
                    anotherField: "a"
                },
            ],
            [
                {
                    arrayToDelete: [0,1,2],
                    anotherField: "a"
                },
                {
                    arrayToDelete: [0,1,2],
                    anotherField: "a"
                },
                {
                    arrayToDelete: [0,1,2],
                    anotherField: "a"
                },
                {   somethingToKeep: 1 },
                {
                    arrayToDelete: [0,1,2],
                    anotherField: "a"
                },
            ],
            [
                {   somethingToKeep: 1 },
                {
                    arrayToDelete: [0,1,2],
                    anotherField: "a"
                },
                {
                    arrayToDelete: [0,1,2],
                    anotherField: "a"
                },
                {
                    arrayToDelete: [0,1,2],
                    anotherField: "a"
                },
                {
                    arrayToDelete: [0,1,2],
                    anotherField: "a"
                },
            ],
        ]
    }
    

    ケース1-フィールドが存在する内部配列要素を削除します

    これは$pullを使用します 配列要素を削除するので、演算子 全体的に。これは、最新のMongoDBで、次のようなステートメントを使用して行います。

    db.collection.updateMany(
      { "scan": {
        "$elemMatch": {
          "$elemMatch": {
            "arrayToDelete": { "$exists": true }
          }
        }
      } },
      {
        "$pull": {
          "scan.$[a]": { "arrayToDelete": { "$exists": true } }
        }
      },
      { "arrayFilters": [
          {  "a": { "$elemMatch": { "arrayToDelete": { "$exists": true } } } }
        ]
      }
    )
    

    これにより、一致するすべてのドキュメントが次のように変更されます:

    {
            "_id" : ObjectId("5ca1c36d9e31550a618011e2"),
            "field" : "value",
            "field2" : "value",
            "scan" : [
                    [
                            {
                                    "somethingToKeep" : 1
                            }
                    ],
                    [
                            {
                                    "somethingToKeep" : 1
                            }
                    ],
                    [
                            {
                                    "somethingToKeep" : 1
                            }
                    ]
            ]
    }
    

    そのため、そのフィールドを含むすべての要素が削除されます。

    ケース2-一致したフィールドを内部要素から削除するだけです

    ここで$unsetを使用します 。 「ハードインデックス」とは少し異なります。 あなたがやっていたバージョン:

    db.collection.updateMany(
      { "scan": {
        "$elemMatch": {
          "$elemMatch": {
            "arrayToDelete": { "$exists": true }
          }
        }
      } },
      { "$unset": { "scan.$[].$[].arrayToDelete": ""  } }
    )
    

    これにより、一致するすべてのドキュメントが次のように変更されます。

    {
            "_id" : ObjectId("5ca1c4c49e31550a618011e3"),
            "field" : "value",
            "field2" : "value",
            "scan" : [
                    [
                            {
                                    "anotherField" : "a"
                            },
                            {
                                    "somethingToKeep" : 1
                            },
                            {
                                    "anotherField" : "a"
                            },
                            {
                                    "anotherField" : "a"
                            },
                            {
                                    "anotherField" : "a"
                            }
                    ],
                    [
                            {
                                    "anotherField" : "a"
                            },
                            {
                                    "anotherField" : "a"
                            },
                            {
                                    "anotherField" : "a"
                            },
                            {
                                    "somethingToKeep" : 1
                            },
                            {
                                    "anotherField" : "a"
                            }
                    ],
                    [
                            {
                                    "somethingToKeep" : 1
                            },
                            {
                                    "anotherField" : "a"
                            },
                            {
                                    "anotherField" : "a"
                            },
                            {
                                    "anotherField" : "a"
                            },
                            {
                                    "anotherField" : "a"
                            }
                    ]
            ]
    }
    

    したがって、すべてがまだそこにありますが、識別されたフィールドだけが各内部配列ドキュメントから削除されています。

    ケース3-アレイ内の「すべて」を実際に削除したかったのです。

    これは、実際には$setを使用する単純なケースです。 以前にあったものをすべて消去します:

    db.collection.updateMany(
      { "scan": {
        "$elemMatch": {
          "$elemMatch": {
            "arrayToDelete": { "$exists": true }
          }
        }
      } },
      { "$set": { "scan": []  } }
    )
    

    結果がかなり期待できる場所:

    {
            "_id" : ObjectId("5ca1c5c59e31550a618011e4"),
            "field" : "value",
            "field2" : "value",
            "scan" : [ ]
    }
    

    では、これらはすべて何をしているのでしょうか?

    最初に表示されるのは、クエリ述語です。 。これは一般的に、一致していないこと、さらには「試行」していないことを確認することをお勧めします 更新しようとしているパターンのデータさえ含まれていないドキュメントで更新条件が満たされるようにするため。ネストされた配列は難しい せいぜい、そして実際的な場合は、あなたがしばしば「本当に意味する」のように、それらを避けるべきです。 実際には、あなたが「考える」ことを表す追加の属性を持つ単一の配列で表されます ネスティング 実際にやっています。

    しかし、彼らが難しいという理由だけで 不可能を意味するものではありません 。 $elemMatchを理解する必要があるだけです :

    db.colelction.find(
      { "scan": {
        "$elemMatch": {
          "$elemMatch": {
            "arrayToDelete": { "$exists": true }
          }
        }
      }}
    )
    

    これが基本的なfind() たとえば、$elemMatchに基づいて一致します 外部の条件 配列は別の$elemMatchを使用します 内部の別の条件に一致させるため 配列。これは「表示される」 単一の述語になります。次のようなもの:

    "scan.arrayToDelete": { "$exists": true }
    

    ただ動作しません。どちらもしません:

    "scan..arrayToDelete": { "$exists": true }
    

    「ダブルドット」で.. それは基本的には有効ではないからです。

    これがクエリ述語です。 処理する必要のある「ドキュメント」と一致しますが、残りは実際に*更新する部分を決定するために適用されます。

    ケース1 $pullするために 内部から 配列の場合、最初に外部のどの要素を識別できる必要があります。 配列には、更新するデータが含まれています。それが"scan.$[a]"です。 位置フィルタリングされた$[<identifier>]を使用して実行しています オペレーター。

    その演算子は基本的に転置 一致したインデックス (したがって、多く それらのうち)別の述語への配列内 これは、updateの3番目のセクションで定義されています arrayFiltersを使用したスタイルコマンド セクション。このセクションでは、基本的に、名前付き識別子の観点から満たす必要のある条件を定義します。

    この場合、「識別子」の名前はaです。 、これはarrayFiltersで使用されるプレフィックスです エントリ:

      { "arrayFilters": [
          {  "a": { "$elemMatch": { "arrayToDelete": { "$exists": true } } } }
        ]
      }
    

    実際の更新ステートメントとの関連で取得 パート:

      {
        "$pull": {
          "scan.$[a]": { "arrayToDelete": { "$exists": true } }
        }
      },
    

    次に、"a"の観点から 外部の識別子である "scan"から最初に内側に配列要素 の場合、元のクエリ述語の場合と同じ条件が適用されます。 ただし、「内」から 最初 $elemMatch 声明。したがって、これは基本的に、すでに「内部を見る」という観点からは「クエリ内のクエリ」と考えることができます。 各アウターのコンテンツ 要素。

    同じように、$pull 「クエリ内のクエリ」のように機能します 配列の要素の観点からも、独自の引数が適用されるという点で。したがって、arrayToDeleteだけです 代わりに存在するフィールド:

      // This would be wrong! and do nothing :(
      {
        "$pull": {
          "scan.$[a]": { "$elemMatch": { "arrayToDelete": { "$exists": true } } }
        }
      }
    

    しかし、それはすべて$pullに固有のものです 、およびその他のものにはさまざまなケースがあります:

    ケース2 $unsetだけにしたい場所を確認します 名前付きフィールド。フィールドに名前を付けるだけなので、とても簡単なようですよね?以下は私たちが以前に知っていたものから明らかに正しくないので、正確にはそうではありません:

      { "$unset": { "scan.arrayToDelete": ""  } } // Not right :(
    

    そしてもちろん、すべての配列インデックスに注意するのは面倒です:

      { "$unset": { 
        "scan.0.0.arrayToDelete": "",
        "scan.0.1.arrayToDelete": "",
        "scan.0.2.arrayToDelete": "",
        "scan.0.3.arrayToDelete": "",  // My fingers are tired :-<
      } }
    

    これが、すべての$[]の位置の理由です。 オペレーター。これはもう少し「ブルートフォース」です 位置フィルタリングされた$[<identifier>]より その中で、別の述語と一致する代わりに arrayFilters内で提供されます 、これが単純に行うことは、すべてに適用されることです。 その「インデックス」の配列コンテンツ内。これは基本的に、「すべてのインデックス」を実際に言う方法です。 恐ろしいのようにすべてを入力せずに 上記のケース。

    したがって、すべての場合ではありません 、しかしそれは確かに$unsetに適しています それは非常に具体的なパスの命名を持っているからです もちろん、そのパスが配列のすべての要素と一致しない場合は問題になりません。

    あなたはできた 引き続きarrayFiltersを使用します 位置フィルタリングされた$[<identifier>] 、しかしここではやり過ぎでしょう。さらに、他のアプローチを示すことは害にはなりません。

    しかしもちろん、どのように理解する価値があるでしょう。 まさにそのステートメントは見えるので、:

    db.collection.updateMany(
      { "scan": {
        "$elemMatch": {
          "$elemMatch": {
            "arrayToDelete": { "$exists": true }
          }
        }
      } },
      { "$unset": { "scan.$[a].$[b].arrayToDelete": ""  } },
      {
        "arrayFilters": [
          { "a": { "$elemMatch": { "arrayToDelete": { "$exists": true } } } },
          { "b.arrayToDelete": { "$exists": true } },
        ]
      }
    )
    

    "b.arrayToDelete"に注意してください 最初は期待したものではないかもしれませんが、"scan.$[a].$[b]での位置付けを考えると bからのように本当に意味があるはずです 要素名は、示されているように「ドット表記」を介して到達します。そして実際にはどちらの場合も。繰り返しになりますが、$unset とにかく名前付きフィールドにのみ適用されるため、選択基準は実際には必要ありません。

    そしてケース3必要がないのであれば、それは非常に簡単です。 このコンテンツを削除した後、配列内に他のものを保持するため(つまり、$pull これに一致するフィールドはのみでした そこにあるもの、または$unset そのことについては)、それなら単に他のものをいじらないで、アレイをワイプする

    これは、名前付きフィールドを持つドキュメントがのみであるかどうかを明確にするためのポイントに従って考慮する場合、重要な違いです。 ネストされた配列内の要素であり、実際、名前付きキーはのみでした。 文書に存在するもの。

    $pullを使用するという理由で ここに示されているように、そしてそれらの条件下であなたは得るでしょう:

    {
            "_id" : ObjectId("5ca321909e31550a618011e6"),
            "field" : "value",
            "field2" : "value",
            "scan" : [
                [ ],
                [ ],
                [ ]
            ]
    }
    

    または、$unsetを使用します :

    {
            "_id" : ObjectId("5ca322bc9e31550a618011e7"),
            "field" : "value",
            "field2" : "value",
            "scan" : [
                [{ }, { }, { }, { }],
                [{ }, { }, { }, { }],
                [{ }, { }, { }, { }]
            ]
    }
    

    どちらも明らかに望ましくありません。したがって、arrayToDeleteの場合は、当然のことです。 フィールドはのみでした そこにあったコンテンツ、そしてすべてを削除する最も論理的な方法 単に配列を空の配列に置き換えることです。または実際に$unset ドキュメントプロパティ全体。

    ただし、これらすべての「派手なもの」に注意してください。 ($setを除く もちろん)少なくともMongoDB3.6が必要である必要があります この機能を使用するために利用できます。

    それよりも古いバージョンのMongoDBをまだ実行している場合(そして、執筆時点では、公式サポートがこの日付からわずか5か月でなくなるため、実際にはそうすべきではありません)、複数の更新方法に関する他の既存の回答mongodbの配列要素は実際にはあなたのためです。



    1. spring-redisがリモートホストに接続できません

    2. Ubuntu18.04にMongoDBをインストールする方法

    3. コアデータ構造タイプ別の上位のRedisユースケース

    4. Redis-期限切れのインデックスは削除されません