在 MongoDB 中,findAndAmendment 和 update 的区别是什么?

我对 MongoDB 中的 findAndModify方法有点困惑。与 update方法相比,它的优点是什么?对我来说,它似乎只是先返回该项,然后再更新它。但是为什么我需要先退货呢?我阅读了 MongoDB: 权威指南,它说它对于操作队列和执行其他需要 get-and-set 样式原子性的操作非常方便。但我不明白它是怎么做到的。有人能给我解释一下吗?

65842 次浏览

如果您获取一个项目,然后更新它,那么在这两个步骤之间可能存在另一个线程的更新。如果您首先更新一个项目,然后再获取它,那么可能会有另一个更新在中间,您将获得一个与您更新的项目不同的项目。

“原子地”执行这个操作意味着您可以保证返回的是您正在更新的完全相同的项——也就是说,在这两个操作之间不会发生任何其他操作。

一个有用的用例类别是计数器和类似的用例。例如,看一下这段代码(MongoDB 测试之一) : Find _ and _ modfy4. js .

因此,使用 findAndModify,您可以递增计数器并得到它的递增 比较: 如果您(A)分两步执行此操作,并且 其他人(B)在你的步骤之间做同样的操作,然后 A 和 B 可能 得到相同的最后一个计数器值,而不是两个不同的(只是一个可能问题的例子)。

findAndModify返回文档,更新不返回。

如果我正确理解了 Dwight Merriman (mongoDB 的原始作者之一) ,那么使用 update 修改单个文档即(“ multi”: false }也是原子级的。目前,它还应该比使用 findAndModify进行等效更新更快。

摘自 MongoDB 文档(加重语气) :

  • 默认情况下,两个操作都修改一个文档。

  • 如果有多个文档符合更新条件,那么对于 findAndAmendment () ,可以指定排序将提供对要更新的文档的某种控制措施。 对于 update ()方法的默认行为,当多个文档匹配时,您无法指定要更新的单个文档。

  • 默认情况下,findAndAmendment ()方法 返回预修改版本的 文件。 Update ()方法返回一个包含操作状态的 WriteResult 对象。若要返回更新后的文档,请使用 find ()方法。但是,其他更新可能在更新和文献检索之间修改了文档。另外,如果更新只修改了一个文档,但是匹配了多个文档,则需要使用其他逻辑来识别更新的文档。

  • 在 MongoDB 3.2之前,您不能指定 findAndModfy ()的写关注点来覆盖默认的写关注点,而在 MongoDB 2.6之后,您可以将 可以指定写关注点指定为 update ()方法。

修改单个文档时,findAndAmendment ()和 update ()方法都会自动更新文档。

我们对 Counter 操作(inc 或 dec)和其他单个字段的 mutate case 使用 findAndAmendment ()。将我们的应用程序从 Couchbase 迁移到 MongoDB,我发现这个 API 可以替换执行 GetAndlock ()的代码,在本地修改内容,替换()以保存,然后再次获取()以获取更新后的文档。对于 mongoDB,我只使用了这个 API 来返回更新后的文档。

这是一个老问题,但也是一个重要的问题,其他的答案只是让我想到了更多的问题,直到我意识到: 这两种方法非常相似,在许多情况下,您可以使用其中一种。

  • findAndModifyupdate都在单个请求中执行原子更改,例如递增计数器; 实际上,<query><update>参数基本相同
  • 对于这两种情况,当服务器找到与查询匹配的文档时,原子变化会直接发生在该文档上,即在服务器确认查询有效并应用更新的那一毫秒内对该文档进行内部写锁

没有用户可以获得的系统级写锁或信号量。句号。MongoDB 故意不让签出文档然后更改它然后写回它变得容易,同时以某种方式阻止其他人在此期间更改该文档。(虽然开发人员可能认为他们需要这样做,但是在可伸缩性和并发性方面,这通常是一种反模式... ... 作为一个简单的例子,假设一个客户端获得写锁,然后在持有它的时候被关闭。如果您真的想要一个写锁,您可以在文档中创建一个,并使用原子更改来比较和设置它,然后确定您自己的恢复过程来处理放弃的锁,等等。但如果你走那条路,就要小心了。)

据我所知,这里有 两种主要的方法不同:

  • 如果你想在更新时获得文档的副本: 只有 findAndModify允许这个 ,在更新后返回原始(默认)或者 new记录,如上所述; 在 update中,你只能获得 WriteResult,而不是文档,当然在读取之前或之后立即读取文档并不能防止另一个进程在读取和更新之间改变记录
  • 如果有多个潜在的匹配文档 : findAndModify只改变一个,并允许您自定义 sort来指示应该改变哪一个; update可以改变所有与 multi虽然它默认只有一个,但不让你说哪一个

因此,HungryCoder 说的有道理,即 update更有效率可以在其限制下生存(例如,您不需要阅读文档; 当然,如果您正在更改多个记录)。但是对于许多原子更新来说,需要文档,而 findAndModify在那里是必需的。