【发布时间】:2013-04-27 20:29:39
【问题描述】:
正如标题所说,我想通过_id对文档执行查找(一个),如果不存在,则创建它,然后无论是找到它还是创建它,都在回调中返回.
如果它存在,我不想更新它,就像我读过的 findAndModify 一样。我在 Stackoverflow 上看到了许多其他关于此的问题,但同样,不想更新任何内容。
我不确定是否通过创建(不存在),这实际上是每个人都在谈论的更新,这一切都令人困惑:(
【问题讨论】:
正如标题所说,我想通过_id对文档执行查找(一个),如果不存在,则创建它,然后无论是找到它还是创建它,都在回调中返回.
如果它存在,我不想更新它,就像我读过的 findAndModify 一样。我在 Stackoverflow 上看到了许多其他关于此的问题,但同样,不想更新任何内容。
我不确定是否通过创建(不存在),这实际上是每个人都在谈论的更新,这一切都令人困惑:(
【问题讨论】:
从 MongoDB 2.4 开始,不再需要依赖唯一索引(或任何其他解决方法)来进行原子 findOrCreate 类操作。
这要感谢 the $setOnInsert operator 2.4 的新功能,它允许您指定仅在插入文档时才发生的更新。
这与upsert 选项结合使用,意味着您可以使用findAndModify 来实现类似findOrCreate 的原子操作。
db.collection.findAndModify({
query: { _id: "some potentially existing id" },
update: {
$setOnInsert: { foo: "bar" }
},
new: true, // return new doc if one is upserted
upsert: true // insert the document if it does not exist
})
由于$setOnInsert 只影响正在插入的文档,如果找到现有的文档,则不会进行任何修改。如果不存在文档,它将使用指定的_id 更新插入一个,然后执行仅插入集。在这两种情况下,都会返回文档。
【讨论】:
collection.findAndModify({_id:'theId'}, <your sort opts>, {$setOnInsert:{foo: 'bar'}}, {new:true, upsert:true}, callback)。见the docs
db.collection.findAndModify({query: {_id: "some potentially existing id"}, update: {$setOnInsert: {foo: "bar"}}, new: true, upsert: true}))insert(upsert)ed一个文档,你应该考虑使用@987654332 @。如果插入了文档,则返回{"acknowledged": true, "matchedCount": 0, "modifiedCount": 0, "upsertedId": ObjectId("for newly inserted one")},如果文档已存在,则返回{"acknowledged": true, "matchedCount": 1, "modifiedCount": 0}。
findOneAndUpdate、findOneAndReplace 或 findOneAndDelete 的风格中已被弃用
使用最新的驱动程序(> 版本 2),您将使用 findOneAndUpdate,因为 findAndModify 已弃用。新方法有 3 个参数,filter、update 对象(其中包含您的默认属性,应该为新对象插入)和options,您必须在其中指定 upsert 操作。
使用 promise 语法,它看起来像这样:
const result = await collection.findOneAndUpdate(
{ _id: new ObjectId(id) },
{
$setOnInsert: { foo: "bar" },
},
{
returnOriginal: false,
upsert: true,
}
);
const newOrUpdatedDocument = result.value;
【讨论】:
它有点脏,但你可以插入它。
确保键上有一个唯一的索引(如果你使用 _id 没关系,它已经是唯一的了)。
这样,如果元素已经存在,它将返回一个您可以捕获的异常。
如果不存在,将插入新文档。
更新:在MongoDB Documentation上详细解释了这种技术
【讨论】:
这是我所做的(Ruby MongoDB 驱动程序):
$db[:tags].update_one({:tag => 'flat'}, {'$set' => {:tag => 'earth' }}, { :upsert => true })}
如果存在则更新,不存在则插入。
【讨论】: