防止同时访问 Mongoose 中的文档

Posted

技术标签:

【中文标题】防止同时访问 Mongoose 中的文档【英文标题】:Preventing concurrent access to documents in Mongoose 【发布时间】:2016-09-13 03:27:06 【问题描述】:

我的服务器应用程序(使用 node.js、mongodb、mongoose)有一个文档集合,重要的是两个客户端应用程序不能在没有看到彼此修改的情况下同时修改它们。

为了防止这种情况,我添加了一个简单的文档版本控制系统:架构上的预挂钩,用于检查文档的版本是否有效(即不高于客户端上次读取的版本)。乍一看,它工作正常:

// Validate version number
UserSchema.pre("save", function(next) 
  var user = this

  user.constructor.findById(user._id, function(err, userCurrent)  // userCurrent is the user that is currently in the db
    if (err) return next(err)
    if (userCurrent == null) return next()

    if(userCurrent.docVersion > user.docVersion) 
      return next(new Error("document was modified by someone else"))
     else 
      user.docVersion = user.docVersion + 1
      return next()
    
  )
)

问题如下:

当两个客户端应用程序同时保存一个用户文档时,这些可能会在预挂钩和实际保存操作之间交错?我的意思如下,想象时间从左到右,v 是版本号(通过保存保留):

App1:  findById(pre)[v:1]                                   save[v->2]
App2:                      findById(pre)[v:1]   save[v->2]

导致 App1 保存了同时(被 App2)修改过的东西,它没有办法注意到它被修改了。 App2 的更新完全丢失。

我的问题可能归结为:Mongoose pre-hook 和 save 方法是否发生在一个原子步骤中?

如果没有,您能否给我一个关于如何解决此问题的建议,以免更新丢失?

谢谢!

【问题讨论】:

【参考方案1】:

MongoDB 有findAndModify,对于单个匹配文档,它是一个原子操作。

Mongoose 有多种使用这种方法的方法,我认为它们会适合您的用例:

Model.findOneAndUpdate() Model.findByIdAndUpdate() Model.findOneAndRemove() Model.findByIdAndRemove()

另一种解决方案(Mongoose 自己也使用它的own document versioning)是使用Update Document if Current 模式。

【讨论】:

谢谢,这行得通。尤其是您建议的模式,因为它允许在尝试更新之前检查文档版本。

以上是关于防止同时访问 Mongoose 中的文档的主要内容,如果未能解决你的问题,请参考以下文章

无法通过 Mongo(mongoose)中的点符号搜索子文档 [重复]

无法通过 Mongo(mongoose)中的点符号搜索子文档 [重复]

Mongo - 如果子文档数组中的对象具有值,则添加字段

通过 express、mongoose 和 angular 删除 mongo 文档时出现 404

如何从 mongoose 的 mongo 文档中返回一个数组?

mongo+mongoose+express