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

MongoDBを使用したネストされた配列の更新

    一般的な範囲と説明

    ここで行っていることにいくつか問題があります。まず、クエリ条件。いくつかの_idを参照しています 必要のない値であり、そのうちの少なくとも1つがトップレベルにない値。

    「ネストされた」値を取得し、その_idを推定するため 値は一意であり、他のドキュメントには表示されません。クエリフォームは次のようになります。

    Model.update(
        { "array1.array2._id": "123" },
        { "$push": { "array1.0.array2.$.answeredBy": "success" } },
        function(err,numAffected) {
           // something with the result in here
        }
    );
    

    これで実際に機能しますが、実際には機能しないのは非常に正当な理由があるため、実際に機能するのはまぐれです。

    重要な読み物は、位置$の公式ドキュメントにあります 「ネストされた配列」の件名の演算子。これが言うことは:

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

    具体的には、位置プレースホルダーに一致して返される要素は、最初のからのインデックスの値です。 一致する配列。これは、あなたの場合、「最上位」レベルの配列の一致するインデックスを意味します。

    したがって、示されているクエリ表記を見ると、最初のが「ハードコーディング」されています。 (または0 index)は最上位配列の位置であり、「array2」内の一致する要素もゼロインデックスエントリであることが起こります。

    これを示すために、一致する_idを変更できます 値を「124」にすると、結果は$pushになります _idを使用した要素への新しいエントリ 「123」は両方とも「array1」のゼロインデックスエントリにあり、プレースホルダーに返される値です。

    これが、配列のネストに関する一般的な問題です。レベルの1つを削除しても、$pushを実行できます。 「最上位」配列の正しい要素に移動しますが、それでも複数のレベルがあります。

    示されているように更新の問題が発生するため、配列をネストしないようにしてください。

    一般的なケースは、あなたが「考える」ものを「レベル」にし、実際にこれらを最終的な詳細項目の「属性」にすることです。たとえば、質問の構造の「フラット化された」形式は、次のようになります。

     {
       "answers": [
         { "by": "success", "type2": "123", "type1": "12" }
       ]
     }
    

    または、内部配列を受け入れる場合でも、$push のみ、更新されることはありません:

     {
       "array": [
         { "type1": "12", "type2": "123", "answeredBy": ["success"] },
         { "type1": "12", "type2": "124", "answeredBy": [] }
       ]
     }
    

    どちらも、位置$の範囲内でアトミック更新に役立ちます オペレーター

    MongoDB3.6以降

    MongoDB 3.6から、ネストされた配列を操作するために利用できる新機能があります。これは、位置フィルタリングされた$[<identifier>]を使用します 特定の要素に一致し、arrayFiltersを介してさまざまな条件を適用するための構文 更新ステートメント内:

    Model.update(
      {
        "_id": 1,
        "array1": {
          "$elemMatch": {
            "_id": "12","array2._id": "123"
          }
        }
      },
      {
        "$push": { "array1.$[outer].array2.$[inner].answeredBy": "success" }
      },
      {
        "arrayFilters": [{ "outer._id": "12" },{ "inner._id": "123" }] 
      }
    )
    

    "arrayFilters" .update()のオプションに渡されたもの または.updateOne().updateMany().findOneAndUpdate() または.bulkWrite() methodは、updateステートメントで指定された識別子に一致する条件を指定します。指定された条件に一致する要素が更新されます。

    構造は「ネスト」されているため、実際には、示されているようにフィルター定義の「配列」で指定されている「複数のフィルター」を使用します。マークされた「識別子」は、位置フィルタリングされた$[<identifier>]との照合に使用されます ステートメントの更新ブロックで実際に使用される構文。この場合、inner およびouter ネストされたチェーンで指定された各条件に使用される識別子です。

    この新しい拡張により、ネストされた配列コンテンツの更新が可能になりますが、そのようなデータの「クエリ」の実用性にはあまり役立たないため、前に説明したのと同じ注意事項が適用されます。

    あなたは通常、実際には「属性」として表現することを「意味」します。たとえ脳が最初に「入れ子」と考えていたとしても、それは通常、「前の関係部分」が一緒になっていると信じる方法に対する反応です。実際には、もっと非正規化する必要があります。

    これらの新しい更新演算子は、最初のだけでなく、実際には「複数の配列要素」と一致して更新されるため、mongodbで複数の配列要素を更新する方法も参照してください。 、これは位置更新の以前のアクションです。

    皮肉なことに、これは.update()の"options"引数で指定されているためです。 メソッドと同様に、構文は通常、最近のすべてのリリースドライバーバージョンと互換性があります。

    ただし、これはmongoには当てはまりません。 シェル、メソッドがそこで実装される方法(「下位互換性のために皮肉なことに」)arrayFilters 引数は、以前のMongoDBサーバーバージョンおよび「レガシー」.update()との「下位互換性」を提供するためにオプションを解析する内部メソッドによって認識および削除されません。 API呼び出し構文。

    したがって、mongoでコマンドを使用する場合 シェルまたはその他の「シェルベース」の製品(特にRobo 3T)には、3.6以降の開発ブランチまたは製品リリースの最新バージョンが必要です。

    positional all $[]も参照してください。 これも「複数の配列要素」を更新しますが、指定された条件には適用されず、すべてに適用されます それが目的のアクションである配列内の要素。



    1. MongoDB:パスで見つかった位置(つまり'$')要素が多すぎます

    2. Mongodb配列$pushおよび$pull

    3. Redis-Cliを使用したレイテンシーの理解

    4. MongoDB deleteOne()