186

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

4

6 回答 6

168

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

以“原子”方式进行操作意味着您可以保证获得与您正在更新的完全相同的项目——即在这两者之间不会发生其他操作。

于 2012-05-28T03:21:01.797 回答
57

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

如果我正确理解 Dwight Merriman(mongoDB 的原作者之一),使用 update 修改单个文档 ie("multi":false} 也是原子的。目前,它也应该比使用findAndModify.

于 2012-11-16T03:47:53.883 回答
33

来自MongoDB 文档(添加了重点):

  • 默认情况下,这两个操作都会修改一个文档。但是,带有 multi 选项的 update() 方法可以修改多个文档

  • 如果多个文档与更新条件匹配,对于 findAndModify(),您可以指定一种排序来提供对要更新哪个文档的某种控制措施。使用 update() 方法的默认行为,当多个文档匹配时,您无法指定要更新哪个单个文档。

  • 默认情况下, findAndModify() 方法返回文档的预修改版本。要获取更新的文档,请使用新选项。update() 方法返回一个包含操作状态的 WriteResult 对象。要返回更新后的文档,请使用 find() 方法。但是,其他更新可能在您的更新和文档检索之间修改了文档。此外,如果更新只修改了单个文档但匹配了多个文档,您将需要使用额外的逻辑来识别更新的文档。

  • 在 MongoDB 3.2 之前,您无法为 findAndModify() 指定写入关注点以覆盖默认的写入关注点,而从 MongoDB 2.6 开始,您可以为 update() 方法指定写入关注点。

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

于 2015-09-29T09:00:33.637 回答
10

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

因此,随着findAndModify您递增计数器并一步获得其递增值。比较:如果您 (A) 分两步执行此操作,而其他人 (B) 在您的步骤之间执行相同的操作,则 A 和 B 可能会获得相同的最后一个计数器值,而不是两个不同的(只是可能问题的一个示例)。

于 2012-05-28T12:20:32.830 回答
2

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

  • 两者findAndModifyupdate在单个请求中执行原子更改,例如递增计数器;事实上<query><update>参数在很大程度上是相同的
  • 对于这两者,当服务器找到与查询匹配的文档时,原子更改直接发生在文档上,即在服务器确认查询有效并应用更新的几分之一毫秒内对该文档进行内部写锁定

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

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

  • 如果您在更新时想要一份文档副本:只findAndModify允许 thisnew ,如前所述,在更新后返回原始(默认)或记录;update你只得到一个,WriteResult而不是文档,当然,在之前或之后立即阅读文档并不能保护你免受另一个过程的影响,也可以在你的阅读和更新之间更改记录
  • 如果可能有多个匹配的文档findAndModify仅更改一个,并允许您自定义sort以指示应该更改哪个;update可以改变所有的multi虽然它默认只有一个,但不会让你说哪一个

Thus it makes sense what HungryCoder says, that update is more efficient where you can live with its restrictions (eg you don't need to read the document; or of course if you are changing multiple records). But for many atomic updates you do want the document, and findAndModify is necessary there.

于 2021-03-07T23:34:28.483 回答
-1

我们将 findAndModify() 用于计数器操作(inc 或 dec)和其他单字段变异情况。将我们的应用程序从 Couchbase 迁移到 MongoDB,我发现这个 API 可以替换执行 GetAndlock() 的代码,在本地修改内容,replace() 保存并再次 Get() 以获取更新的文档。使用 mongoDB,我只使用了这个返回更新文档的 API。

于 2020-05-26T01:47:37.873 回答