web-dev-qa-db-ja.com

MongoDBは配列内の複数のサブドキュメントをそれぞれ条件に応じて更新します

私はこのような文書を持っています:

{
    wid: 1,
    items: [
        {nid: 1, sent: 900},
        {nid: 2, sent: 12},
        {nid: 3, sent: 0},
        {nid: 4, sent: 1}
    ]
}

ここで、このドキュメントを別の場所から計算したオブジェクトで更新したいとします。

# All for wid:1, a mapping of nid:sent
# These values should be added to values already in the DB
{
    2: 37,
    3: 58,
    4: 172
}

したがって、更新後、次のようなものが必要になります。

{
    wid: 1,
    items: [
        {nid: 1, sent: 900},
        {nid: 2, sent: 49},
        {nid: 3, sent: 58},
        {nid: 4, sent: 173}
    ]
}

とにかくこれを1つの更新クエリだけで行うことはありますか?

私が知っていることはうまくいく->

db.test.update_one({wid: 1, 'items.nid': 2}, {$inc: {'items.$.sent': 37}})
db.test.update_one({wid: 1, 'items.nid': 3}, {$inc: {'items.$.sent': 37}})
db.test.update_one({wid: 1, 'items.nid': 4}, {$inc: {'items.$.sent': 172}})

しかし、それはO(n)発行された更新クエリであり、これは、MongoDBに固執することを選択したすべての理由と本当に矛盾しています。

ありがとう!

1
SpiXel

arrayFiltersプロパティを使用します。

db.getCollection("test").updateOne(
    {
        "wid": 1
    },
    {
        $inc: {
            "items.$[aa].sent": 37,
            "items.$[bb].sent": 58,
            "items.$[cc].sent": 172
        }
    },
    {
        upsert: false,            
        arrayFilters: [
            { "aa.nid": 2 },
            { "bb.nid": 3 },
            { "cc.nid": 4 }
        ]
    }
);

作成した名前付き識別子ごとに(例ではaabbcc)、arrayFilters配列に一致するドキュメントを作成する必要があります。

1