MongoDB原子"findOrCreate":findOne,如果不存在则插入,但不更新

Dis*_*pol 108 mongodb node.js

正如标题所说,我想通过_id执行文档的查找(一个),如果不存在,则创建它,然后是否找到它或者是否已创建它,让它在回调中返回.

如果它存在,我不想更新它,因为我读过findAndModify.我在Stackoverflow上看到了很多关于此问题的其他问题,但同样,不希望更新任何内容.

我不确定是否通过创建(不存在),这实际上是每个人都在谈论的更新,它都是如此令人困惑:(

num*_*407 186

从MongoDB 2.4开始,不再需要依赖于原子findOrCreate类操作的唯一索引(或任何其他解决方法).

这要归功于2.4 $setOnInsert操作员,它允许您指定仅在插入文档时才会发生的更新.

这与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
})
Run Code Online (Sandbox Code Playgroud)

由于$setOnInsert仅影响要插入的文档,如果找到现有文档,则不会进行任何修改.如果不存在任何文档,它将使用指定的_id复制一个文档,然后执行仅插入集.在这两种情况下,都会返回文档.

  • 有没有办法知道文件是否已更新或插入? (7认同)
  • 似乎在`findOneAndUpdate`,`findOneAndReplace`或`findOneAndDelete`的味道中被弃用了 (7认同)
  • 不过,在这里需要注意.这仅适用于findAndModify/findOneAndUpdate/updateOne的选择器通过_id唯一标识一个文档.否则,upsert将在服务器上拆分为查询和更新/插入.更新仍将是原子的.但是查询和更新一起不会以原子方式执行. (4认同)
  • @Gank如果你使用节点的mongodb本机驱动程序,语法将更像`collection.findAndModify({_ id:'theId'},<your sort opts>,{$ setOnInsert:{foo:'bar'}} ,{new:true,upsert:true},callback)`.参见[文档](http://mongodb.github.io/node-mongodb-native/api-generated/collection.html) (3认同)
  • 如果你想**检查**上面的查询(`db.collection.findAndModify({query:{_ id:"some some existing id"}},请更新:{$ setOnInsert:{foo:"bar"}}, new:true,upsert:true})`)**insert(upsert)ed**一个文档,你应该考虑使用`db.collection.updateOne({_ id:"一些可能存在的id"},{$ setOnInsert:{ foo:"bar"}},{upsert:true})`.它返回`{"confirmged":true,"matchedCount":0,"modifiedCount":0,"upsertedId":ObjectId("for new inserted one")}`如果插入了doc,`{"确认":true, "matchedCount":1,"modifiedCount":0}`如果doc已存在. (3认同)

han*_*aad 10

驱动程序版本> 2

采用最新的驱动程序(> 2版),您将使用findOneAndUpdate作为findAndModify被废弃。这种新方法需要3个参数的filter,该update对象(其中包含您的默认属性,应插入一个新的对象),并options在那里你必须指定更新插入操作。

使用promise语法,它看起来像这样:

const result = await collection.findOneAndUpdate(
  { _id: new ObjectId(id) },
  {
    $setOnInsert: { foo: "bar" },
  },
  {
    returnOriginal: false,
    upsert: true,
  }
);

const newOrUpdatedDocument = result.value;
Run Code Online (Sandbox Code Playgroud)


Mad*_*rco 6

它有点脏,但你可以插入它.

确保密钥上有唯一索引(如果使用_id就可以了,它已经是唯一的).

这样,如果元素已经存在,它将返回一个你可以捕获的异常.

如果不存在,将插入新文档.

更新:MongoDB文档中对此技术的详细说明

  • 这实际上是隔离操作序列的推荐解决方案之一(如果没有找到,则发现然后创建)http://docs.mongodb.org/manual/tutorial/isolate-sequence-of-operations/ (3认同)