MongoDB中findAndModify和更新有什么区别?

时间:2012-05-28 01:27:52

标签: mongodb

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

6 个答案:

答案 0 :(得分:140)

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

以“原子方式”执行此操作意味着您可以保证您正在返回正在更新的完全相同的项目 - 即之间不会发生其他操作。

答案 1 :(得分:50)

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

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

答案 2 :(得分:26)

MongoDB docs(强调添加):

  
      
  • 默认情况下,两个操作都会修改单个文档。但是,update()方法及其多选项可以修改多个文档

  •   
  • 如果多个文档符合更新条件,则对于findAndModify(),可以指定排序,以便对要更新的文档进行一些控制。   使用update()方法的默认行为,您无法指定在多个文档匹配时要更新的单个文档。

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

  •   
  • 您不能指定findAndModify()的写入问题来覆盖默认的写入问题,而从MongoDB 2.6开始,可以为update()方法指定写入问题。 / p>

  •   
     

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

答案 3 :(得分:8)

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

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

答案 4 :(得分:0)

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

答案 5 :(得分:0)

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

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

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

据我所知,方法的区别主要有两种

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

因此,HungryCoder 所说的是有道理的,update 在您可以忍受其限制的情况下更有效(例如,您不需要阅读文档;或者当然,如果您正在更改多个记录)。但是对于许多原子更新,您确实需要文档,而 findAndModify 在那里是必需的。