首页 文章

MongoDB - 更新文档数组中的对象(嵌套更新)

提问于
浏览
172

假设我们有以下集合,我几乎没有问题:

{
    "_id" : ObjectId("4faaba123412d654fe83hg876"),
    "user_id" : 123456,
    "total" : 100,
    "items" : [
            {
                    "item_name" : "my_item_one",
                    "price" : 20
            },
            {
                    "item_name" : "my_item_two",
                    "price" : 50
            },
            {
                    "item_name" : "my_item_three",
                    "price" : 30
            }
    ]
}

1 - 我想增加"item_name":"my_item_two" and if it doesn't exists 的价格,它应该附加到"items"数组 .

2 - 如何同时更新两个字段 . 例如,增加“my_item_three”的价格,同时增加“total”(具有相同的值) .

我更喜欢在MongoDB端执行此操作,否则我必须在客户端(Python)中加载文档并构造更新的文档并将其替换为MongoDB中的现有文档 .

UPDATE 这是我尝试过的,并且工作得很好 IF THE Object Exists

db.test_invoice.update({user_id : 123456 , "items.item_name":"my_item_one"} , {$inc: {"items.$.price": 10}})

但如果密钥不存在则无效 . 它也只更新嵌套对象 . 此命令无法更新“total”字段 .

2 回答

  • 20

    对于问题#1,我们将其分为两部分 . 首先,增加“items.item_name”等于“my_item_two”的任何文档 . 为此,您必须使用位置“$”运算符 . 就像是:

    db.bar.update( {user_id : 123456 , "items.item_name" : "my_item_two" } , 
                    {$inc : {"items.$.price" : 1} } , 
                    false , 
                    true);
    

    请注意,这只会增加任何数组中第一个匹配的子文档(因此,如果数组中的另一个文档的“item_name”等于“my_item_two”,则不会增加) . 但这可能就是你想要的 .

    第二部分比较棘手 . 我们可以将一个新项目推送到没有“my_item_two”的数组,如下所示:

    db.bar.update( {user_id : 123456, "items.item_name" : {$ne : "my_item_two" }} , 
                    {$addToSet : {"items" : {'item_name' : "my_item_two" , 'price' : 1 }} } ,
                    false , 
                    true);
    

    对于你的问题#2,答案更容易 . 要在包含“my_item_three”的任何文档中增加item_three的总数和价格,您可以同时在多个字段上使用$ inc运算符 . 就像是:

    db.bar.update( {"items.item_name" : {$ne : "my_item_three" }} ,
                   {$inc : {total : 1 , "items.$.price" : 1}} ,
                   false ,
                   true);
    
  • 198

    在单个查询中无法执行此操作 . 您必须在第一个查询中搜索文档:

    如果文件存在:

    db.bar.update( {user_id : 123456 , "items.item_name" : "my_item_two" } , 
                    {$inc : {"items.$.price" : 1} } , 
                    false , 
                    true);
    

    其他

    db.bar.update( {user_id : 123456 } , 
                    {$addToSet : {"items" : {'item_name' : "my_item_two" , 'price' : 1 }} } ,
                    false , 
                    true);
    

    无需添加条件 {$ne : "my_item_two" } .

    同样在多线程环境中,你必须要小心,一次只有一个线程可以执行第二个(插入案例,如果没有找到文档),否则将插入重复的嵌入文档 .

相关问题