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

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/10522347/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-09 12:39:06  来源:igfitidea点击:

MongoDB - Update objects in a document's array (nested updating)

mongodb

提问by Majid

Assume we have the following collection, which I have few questions about:

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

{
    "_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 - I want to increase the price for "item_name":"my_item_two" and if it doesn't exists, it should be appended to the "items" array.

1 - 我想提高 "item_name":"my_item_two" 的价格,如果它不存在,则应将其附加到 "items" 数组。

2 - How can I update two fields at the same time. For example, increase the price for "my_item_three" and at the same time increase the "total" (with the same value).

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

I prefer to do this on the MongoDB side, otherwise I have to load the document in client-side (Python) and construct the updated document and replace it with the existing one in MongoDB.

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

UPDATEThis is what I have tried and works fine IF THE Object Exists:

更新这是我尝试过的并且在对象存在时工作正常:

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

But if the key doesn't exist it does nothing. Also it only updates the nested object. There is no way with this command to update the "total" field as well.

但如果密钥不存在,它什么都不做。它也只更新嵌套对象。此命令也无法更新“总计”字段。

回答by matulef

For question #1, let's break it into two parts. First, increment any document that has "items.item_name" equal to "my_item_two". For this you'll have to use the positional "$" operator. Something like:

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

Note that this will only increment the first matched subdocument in any array (so if you have another document in the array with "item_name" equal to "my_item_two", it won't get incremented). But this might be what you want.

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

The second part is trickier. We can push a new item to an array without a "my_item_two" as follows:

第二部分比较棘手。我们可以将一个新项目推送到一个没有“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);

For your question #2, the answer is easier. To increment the total and the price of item_three in any document that contains "my_item_three," you can use the $inc operator on multiple fields at the same time. Something like:

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

回答by Udit

There is no way to do this in single query. You have to search the document in first query:

在单个查询中无法做到这一点。您必须在第一个查询中搜索文档:

If document exists:

如果文档存在:

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

Else

别的

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

No need to add condition {$ne : "my_item_two" }.

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

Also in multithreaded enviourment you have to be careful that only one thread can execute the second (insert case, if document did not found) at a time, otherwise duplicate embed documents will be inserted.

同样在多线程环境中,您必须注意一次只有一个线程可以执行第二个线程(如果未找到文档,则插入案例),否则将插入重复的嵌入文档。

回答by KARTHIKEYAN.A

We can use $setoperator to update the nested array inside object filed update the value

我们可以使用$set运算符更新对象字段内的嵌套数组更新值

db.getCollection('geolocations').update( 
   {
       "_id" : ObjectId("5bd3013ac714ea4959f80115"), 
       "geolocation.country" : "United States of America"
   }, 
   { $set: 
       {
           "geolocation.$.country" : "USA"
       } 
    }, 
   false,
   true
);