假设我们有以下集合,我对它没有什么问题:
{
"_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”的价格,同时增加“total”(具有相同的值)。
我更喜欢在MongoDB端这样做,否则我必须在客户端(Python)中加载文档,并构造更新的文档,然后用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);
在单一查询中没有办法做到这一点。您必须在第一个查询中搜索文档:
如果文档存在:
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);
不需要添加条件
同样,在多线程环境中,您必须小心,一次只能有一个线程执行第二个线程(插入的情况下,如果没有找到文档),否则将插入重复的嵌入文档。
我们可以使用
db.getCollection('geolocations').update(
{
"_id" : ObjectId("5bd3013ac714ea4959f80115"),
"geolocation.country" : "United States of America"
},
{ $set:
{
"geolocation.$.country" : "USA"
}
},
false,
true
);