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

アレイ上のmongoDBアップサート

    これはあなたが思うほど単純ではありません、そして実際にあなたがこれの分析を3つの部分に分けたのは興味深いことです。なぜなら、何だと思いますか?それはまさにあなたがしなければならないものです 行う。手順を考えてみましょう:

    1。ドキュメントが存在しない場合は挿入します

    db.collection.update(
        { 
            "clientId":"123456"
        },
        {
            "$setOnInsert": {
                "clientId": "123456",
                "devices": [{
                    "deviceId": "321",
                    "deviceType" : "kindle",
                    "notification" : false
                }]
            }
        },
        { "upsert": true }
    )
    

    だからあなたがしたいのは挿入です 「clientId」が現在存在しない新しいドキュメント。これは、「一意の」キーの衝突を回避するための「アップサート」として実行でき、「一意の」制約がない場合でも、この「アップサート」の性質により、「新しい」ドキュメントが見つからなかった場合にのみ作成できます。 $setOnInsertもあります ここではしないからです この時点で「見つかった」ドキュメントに対して何かをしたい。

    ここではなしがあることに注意してください 配列内の要素を一致させようとします。これは、既存のドキュメントに「その」配列要素がなかったという理由だけで、新しいドキュメントを「作成」したくない可能性があるためです。次のステップに進みます。

    2。ドキュメントが存在する場所でドキュメントの内容を更新します

    db.collection.update(
        { 
            "clientId":"123456",
            "devices": { "$elemMatch": { "deviceId" : "321" } }
        },
        {
            "$set": {
                "devices.$.deviceType" : "kindle",
                "devices.$.notification" : false
            }
        }
    )
    

    ここで、実際に実行する「clientId」のドキュメントを「照合」してみます。 探している「deviceId」にも一致する要素が配列に含まれています。したがって、一致する条件を指定することで、位置$を使用できます。 フィールドを「一致する」位置に設定するための演算子。

    上記のように、これは1つと一致する予定でした 物または何もない したがって、更新が行われたか、行われなかったかのどちらかです。これで、カスケードの最後の部分に移ります:

    3。存在しない配列要素を追加します

    db.collection.update(
        { 
            "clientId":"123456"
        },
        {
            "$addToset": { "devices": {
                "deviceId" : "321",
                "deviceType" : "kindle",
                "notification" : false
            }}
        }
    )
    

    したがって、これは重要 最終段階。その理由は、前述の操作のいずれかが実行された 既存のドキュメントを「作成」または「更新」してから、$addToSetを使用します ここで確実になります 同じ「deviceId」が他の異なる値を持つ別のドキュメントを配列に「プッシュ」しているのではありません。 1つの場合 これらのステージのうち、機能した場合、その要素のすべての値がすでに存在していることがわかり、別の要素を追加することはありません。

    別の順序でそれを行おうとした場合、提示する場合は2つになります 「deviceId」は同じですが、「deviceType」と「notification」の値が異なる配列内のドキュメント。それが最後になる理由です。

    結論

    残念ながら、これらを1つとして組み合わせる簡単な方法はありません。 手術。演算子は単に存在しないため、これは1つのステートメントで実行できるため、必要 3つを実行します あなたが望むことをするために操作を更新します。また、述べたように、注文 これらの更新の申請の割合は重要です 希望する結果が得られるようにします。

    これは現在の「本番」リリースにはまだ存在しませんが、次のリリース(執筆時点では2.6以降)には、更新する新しい構文でこれらの要求を「バッチ処理」する方法があります。

    db.runCommand(
        "update": "collection",
        "updates": [
            { 
                "q": { "clientId":"123456" },
                "u": {
                    "$setOnInsert": {
                        "clientId": "123456",
                        "devices": [{
                        "deviceId": "321",
                        "deviceType" : "kindle",
                        "notification" : false
                    }]
                },
                "upsert": true
            },
            {
                "q": { 
                     "clientId":"123456",
                     "devices": { "$elemMatch": { "deviceId" : "321" } }
                },
                "u": {
                    "$set": {
                        "devices.$.deviceType" : "kindle",
                        "devices.$.notification" : false
                     }
                }
            },
            {
                "q": { "clientId":"123456" },
                "u": {
                    "$addToset": { "devices": {
                        "deviceId" : "321",
                        "deviceType" : "kindle",
                        "notification" : false
                    }}
                }
            }
        ]
    )
    

    ですから、それはまだ 基本的に3つの操作で、少なくともネットワーク経由で送信できます。 一度だけ



    1. MySQLレプリケーション(およびその他)のフェイルオーバー-自動化する必要がありますか?

    2. MongoDBでデータベースを作成する

    3. 使用可能なすべてのキーを取得するためのRedisコマンド?

    4. Redisでソートされたセットを介した逆ページネーション