MongoDB中的findAndModify和update之间有什么区别?


176

我对findAndModifyMongoDB中的方法有些困惑。它比update方法有什么优势?对我来说,它似乎只是先返回该项目,然后再对其进行更新。但是为什么我需要先退货?我读了《MongoDB:权威指南》,它说它对于处理队列和执行其他需要获取和设置样式原子性的操作非常方便。但是我不明白它是如何实现的。有人可以向我解释吗?

Answers:


157

如果您获取一个项目然后进行更新,则这两个步骤之间可能会有另一个线程进行更新。如果先更新一个项目然后取回它,则它们之间可能还会有另一个更新,并且您将获得与已更新项目不同的其他项目。

“以原子方式”进行操作意味着您可以确保完全取回要更新的项目-即在此之间不会发生其他操作。


6
我还是有点困惑。如何findAndModify保证没有其他更新操作干扰它?
12

79
@chaonextdoor findAndModify在启动操作时会获得对数据库的锁定,因此运行时其他任何操作都无法处理。完成操作后,它将释放锁定。
Lycha

4
直到请求的修改部分,findAndModify才真正获得锁。因此,多个进程可以更新同一记录。
Mark Unsworth 2013年

5
@MarkUnsworth用10gen打开了一个支持案例-如果在findAndModify锁定中存在错误,我可以保证您的工程师会尽快修复它。如果是这种情况,虽然我们会看到很多人报告了此行为,但是findAndModify的工作原理是为几乎所有使用它的人设计的-在这种情况下,似乎并没有归结于客户端的逻辑或实现错误,但是在复杂的软件中,当然总会有bug。
Asya Kamsky

5
@AsyaKamsky我当时正在考虑与您争论,但后来意识到您是正确的,所以现在我想对不起您。抱歉!
funkyeah

55

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

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


31

MongoDB文档中(添加了重点):

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

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

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

  • 在MongoDB 3.2之前,您不能为findAndModify()指定写关注以覆盖默认写关注,而自MongoDB 2.6起,您可以为update()方法指定写关注

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


1
您始终可以指定写关注来更新操作。另外,从3.2(从技术上讲是3.1.1)开始,您还可以为findAndModify指定写关注点。jira.mongodb.org/browse/SERVER-6558
Asya Kamsky

我发现在MongDB 3.6中,尽管该文档findAndModify()默认情况下仅修改一个文档并update()可以更新一个或多个文档,但是当我使用时arrayFilters,会findAndModify()更新所有匹配项。也许是一个错误?
WesternGun

没有错误-arrayFilters允许您更新多个数组元素,但它们仍在单个文档中。
Asya Kamsky

10

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

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


0

我们使用findAndModify()进行Counter操作(inc或dec),而其他单个字段则使大小写发生变化。将我们的应用程序从Couchbase迁移到MongoDB时,我发现此API代替了执行GetAndlock()的代码,在本地修改内容,replace()保存并再次获取Get()以取回更新的文档。对于mongoDB,我只使用了一个API,该API返回了更新的文档。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.