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" и если он не существует, он должен быть добавлен в массив "элементы".



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

652   2  

2 ответов:

на вопрос #1, давайте разбить его на две части. Во-первых, увеличьте любой документ, который имеет "элементы.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, Ответ проще. Чтобы увеличить общую сумму и цену item_three в любом документе, содержащем "my_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);

нет необходимости добавлять условие {$ne : "my_item_two" }.

также в многопоточной среде вы должны быть осторожны, что только один поток может выполнить второй (вставить случай, если документ не найден) за один раз, в противном случае будут вставлены дубликаты вложенных документов.

Comments

    Ничего не найдено.