MongoDB - 更新或插入数组中的对象
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/37427610/
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
MongoDB - Update or Insert object in array
提问by Narupon Tee Srisantitham
I have the following collection
我有以下收藏
{
"_id" : ObjectId("57315ba4846dd82425ca2408"),
"myarray" : [
{
userId : ObjectId("570ca5e48dbe673802c2d035"),
point : 5
},
{
userId : ObjectId("613ca5e48dbe673802c2d521"),
point : 2
},
]
}
These are my questions
这些是我的问题
I want to push into myarray if userId doesn't exist, it should be appended to myarray. If userId exists, it should be updated to point.
如果 userId 不存在,我想推入 myarray,它应该附加到 myarray。如果 userId 存在,则应将其更新为指向。
I found this
我找到了这个
db.collection.update({
_id : ObjectId("57315ba4846dd82425ca2408"), "myarray.userId" : ObjectId("570ca5e48dbe673802c2d035")
},{
$set: {"myarray.$.point": 10}
})
But if userId doesn't exist, nothing happens.
但如果 userId 不存在,则什么也不会发生。
and
和
db.collection.update({
_id : ObjectId("57315ba4846dd82425ca2408")
},{
$push: {"myarray": {userId: ObjectId("570ca5e48dbe673802c2d035"), point: 10}}
})
But if userId object already exists, it will push again.
但是如果 userId 对象已经存在,它会再次推送。
What is the best way to do this in MongoDB?
在 MongoDB 中执行此操作的最佳方法是什么?
采纳答案by Flying Fisher
Try this
尝试这个
db.collection.update(
{ _id : ObjectId("57315ba4846dd82425ca2408")},
{ $pull: {"myarray.userId": ObjectId("570ca5e48dbe673802c2d035")}}
)
db.collection.update(
{ _id : ObjectId("57315ba4846dd82425ca2408")},
{ $push: {"myarray": {
userId:ObjectId("570ca5e48dbe673802c2d035"),
point: 10
}}
)
Explination:
in the first statment $pull
removes the element with userId= ObjectId("570ca5e48dbe673802c2d035")
from the array on the document where _id = ObjectId("57315ba4846dd82425ca2408")
说明:在第一个语句$pull
中userId= ObjectId("570ca5e48dbe673802c2d035")
从文档上的数组中删除元素 with_id = ObjectId("57315ba4846dd82425ca2408")
In the second one $push
inserts
this object { userId:ObjectId("570ca5e48dbe673802c2d035"), point: 10 }
in the same array.
在第二个中,$push
将这个对象插入{ userId:ObjectId("570ca5e48dbe673802c2d035"), point: 10 }
到同一个数组中。
回答by Yeti
The accepted answer by Flying Fisher is that the existing record will first be deleted, and then it will be pushed again.
Flying Fisher 接受的答案是先删除现有记录,然后再推送。
A safer approach (common sense) would be to try to update the record first, and if that did not find a match, insert it, like so:
更安全的方法(常识)是先尝试更新记录,如果没有找到匹配项,则插入它,如下所示:
// first try to overwrite existing value
var result = db.collection.update(
{
_id : ObjectId("57315ba4846dd82425ca2408"),
"myarray.userId": ObjectId("570ca5e48dbe673802c2d035")
},
{
$set: {"myarray.$.point": {point: 10}}
}
);
// you probably need to modify the following if-statement to some async callback
// checking depending on your server-side code and mongodb-driver
if(!result.nMatched)
{
// record not found, so create a new entry
// this can be done using $addToSet:
db.collection.update(
{
_id: ObjectId("57315ba4846dd82425ca2408")
},
{
$addToSet: {
myarray: {
userId: ObjectId("570ca5e48dbe673802c2d035"),
point: 10
}
}
}
);
// OR (the equivalent) using $push:
db.collection.update(
{
_id: ObjectId("57315ba4846dd82425ca2408"),
"myarray.userId": {$ne: ObjectId("570ca5e48dbe673802c2d035"}}
},
{
$push: {
myarray: {
userId: ObjectId("570ca5e48dbe673802c2d035"),
point: 10
}
}
}
);
}
This should also give (common sense, untested) an increase in performance, if in most cases the record already exists, only the first query will be executed.
这也应该(常识,未经测试)提高性能,如果在大多数情况下记录已经存在,则只会执行第一个查询。
回答by Sandesh
Unfortunately "upsert" operation is not possible on embedded array. Operators simply do not exist so that this is not possible in a single statement.Hence you must perform two update operations in order to do what you want. Also the order of application for these two updates is important to get desired result.
不幸的是,“upsert”操作在嵌入式阵列上是不可能的。运算符根本不存在,因此这在单个语句中是不可能的。因此,您必须执行两个更新操作才能执行您想要的操作。此外,这两个更新的应用顺序对于获得所需的结果也很重要。
回答by joniba
In MongoDB 3.6 it is now possible to upsert elements in an array.
在 MongoDB 3.6 中,现在可以在数组中插入元素。
回答by Fabio Formosa
I haven't found any solutions based on a one atomic query. Instead there are 3 ways based on a sequence of two queries:
我还没有找到任何基于单原子查询的解决方案。相反,有 3 种基于两个查询序列的方法:
always
$pull
(to remove the item from array), then$push
(to add the updated item to array)db.collection.update( { _id : ObjectId("57315ba4846dd82425ca2408")}, { $pull: {"myarray.userId": ObjectId("570ca5e48dbe673802c2d035")}} ) db.collection.update( { _id : ObjectId("57315ba4846dd82425ca2408")}, { $push: { "myarray": { userId:ObjectId("570ca5e48dbe673802c2d035"), point: 10 } } } )
try to
$set
(to update the item in array if exists), then get the result and check if the updating operation successed or if a$push
needs (to insert the item)var result = db.collection.update( { _id : ObjectId("57315ba4846dd82425ca2408"), "myarray.userId": ObjectId("570ca5e48dbe673802c2d035") }, { $set: {"myarray.$.point": {point: 10}} } ); if(!result.nMatched){ db.collection.update({_id: ObjectId("57315ba4846dd82425ca2408")}, { $addToSet: { myarray: { userId: ObjectId("570ca5e48dbe673802c2d035"), point: 10 } } );
always
$addToSet
(to add the item if not exists), then always$set
to update the item in arraydb.collection.update({_id: ObjectId("57315ba4846dd82425ca2408")}, myarray: { $not: { $elemMatch: {userId: ObjectId("570ca5e48dbe673802c2d035")} } } }, { $addToSet : { myarray: { userId: ObjectId("570ca5e48dbe673802c2d035"), point: 10 } } }, { multi: false, upsert: false}); db.collection.update({ _id: ObjectId("57315ba4846dd82425ca2408"), "myArray.userId": ObjectId("570ca5e48dbe673802c2d035") }, { $set : { myArray.$.point: 10 } }, { multi: false, upsert: false});
总是
$pull
(从数组中删除项目),然后$push
(将更新的项目添加到数组中)db.collection.update( { _id : ObjectId("57315ba4846dd82425ca2408")}, { $pull: {"myarray.userId": ObjectId("570ca5e48dbe673802c2d035")}} ) db.collection.update( { _id : ObjectId("57315ba4846dd82425ca2408")}, { $push: { "myarray": { userId:ObjectId("570ca5e48dbe673802c2d035"), point: 10 } } } )
尝试
$set
(如果存在则更新数组中的项目),然后获取结果并检查更新操作是否成功或是否$push
需要(插入项目)var result = db.collection.update( { _id : ObjectId("57315ba4846dd82425ca2408"), "myarray.userId": ObjectId("570ca5e48dbe673802c2d035") }, { $set: {"myarray.$.point": {point: 10}} } ); if(!result.nMatched){ db.collection.update({_id: ObjectId("57315ba4846dd82425ca2408")}, { $addToSet: { myarray: { userId: ObjectId("570ca5e48dbe673802c2d035"), point: 10 } } );
始终
$addToSet
(如果不存在则添加项目),然后始终$set
更新数组中的项目db.collection.update({_id: ObjectId("57315ba4846dd82425ca2408")}, myarray: { $not: { $elemMatch: {userId: ObjectId("570ca5e48dbe673802c2d035")} } } }, { $addToSet : { myarray: { userId: ObjectId("570ca5e48dbe673802c2d035"), point: 10 } } }, { multi: false, upsert: false}); db.collection.update({ _id: ObjectId("57315ba4846dd82425ca2408"), "myArray.userId": ObjectId("570ca5e48dbe673802c2d035") }, { $set : { myArray.$.point: 10 } }, { multi: false, upsert: false});
1 and 2 ways are unsafe, so transaction must be established to avoid two concurrent requests could push
the same item generating a duplicate.
1 和 2 方式是不安全的,因此必须建立事务以避免两个并发请求可能push
导致同一个项目产生重复。
3 way is safe. $addToSet
add only if the item doesn't exist, otherwise nothing happens. In case of two concurrent requests, only one of them add the missing item to the array.
3路是安全的。$addToSet
仅当项目不存在时才添加,否则什么都不会发生。在两个并发请求的情况下,只有其中一个将缺少的项添加到数组中。
回答by Gagandeep Kalra
array update and create don't mix in under one query, if you care much about atomicity then there's this solution:
数组更新和创建不要混入一个查询中,如果您非常关心原子性,那么有以下解决方案:
normalise your schema to,
将您的架构规范化为,
{
"_id" : ObjectId("57315ba4846dd82425ca2408"),
userId : ObjectId("570ca5e48dbe673802c2d035"),
point : 5
}
回答by Роман Зыков
When you want update or insert value in array try it
当您想在数组中更新或插入值时,请尝试
Object in db
数据库中的对象
key:name,
key1:name1,
arr:[
{
val:1,
val2:1
}
]
Query
询问
var query = {
$inc:{
"arr.0.val": 2,
"arr.0.val2": 2
}
}
.updateOne( { "key": name }, query, { upsert: true }
key:name,
key1:name1,
arr:[
{
val:3,
val2:3
}
]