124

正如标题所说,我想通过_id对文档执行查找(一个),如果不存在,则创建它,然后无论是找到它还是创建它,都在回调中返回它。

如果它存在,我不想更新它,就像我读过 findAndModify 一样。我在 Stackoverflow 上看到了许多其他关于此的问题,但同样,不想更新任何内容。

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

4

4 回答 4

205

从 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
})

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

于 2013-05-03T15:45:11.697 回答
22

驱动程序版本 > 2

使用最新的驱动程序(> 版本 2),您将使用不推荐使用的findOneAndUpdatefindAndModify。新方法有 3 个参数,filterupdate对象(包含您的默认属性,应该为新对象插入),以及options您必须指定 upsert 操作的位置。

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

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

const newOrUpdatedDocument = result.value;
于 2018-04-14T11:15:16.630 回答
6

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

确保键上有一个唯一索引(如果您使用 _id 没关系,它已经是唯一的)。

这样,如果元素已经存在,它将返回您可以捕获的异常。

如果它不存在,则将插入新文档。

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

于 2013-05-03T14:05:39.033 回答
0

这是我所做的(Ruby MongoDB 驱动程序):

$db[:tags].update_one({:tag => 'flat'}, {'$set' => {:tag => 'earth' }}, { :upsert => true })}

如果存在,它将更新它,如果不存在,则插入它。

于 2016-12-06T18:45:52.710 回答