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

假设我们有以下几个关于以下几个问题的集合:

{ "_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” ,如果它不存在 ,它应该被追加到“items”数组。

2 – 如何在同一时间更新两个字段。 例如,增加“my_item_three”的价格,同时增加“总数”(具有相同的值)。

我更喜欢在MongoDB上这样做,否则我必须在客户端(Python)中加载文档,并构build更新后的文档,并将其replace为MongoDB中的现有文档。

更新这是我已经试过,并正常工作, 如果对象存在

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

但如果钥匙不存在,它什么也不做。 而且它只更新嵌套的对象。 这个命令也没有办法更新“total”字段。

对于问题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); 

在单个查询中没有办法做到这一点。 您必须在第一个查询中search文档:

如果文件存在:

 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" }

同样在multithreading的环境中,你必须小心,一次只有一个线程可以执行第二个(插入的情况下,如果文档没有find),否则插入重复的embedded文档。