我的服务器应用程序(使用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方法是在一个原子步骤中发生的吗?
如果没有,你能否就如何解决这个问题给我一个建议,以免任何更新丢失?
谢谢!
答案 0 :(得分:2)
MongoDB有findAndModify
,对于单个匹配文档,它是一个原子操作。
Mongoose有各种使用此方法的方法,我认为它们适合您的用例:
Model.findOneAndUpdate()
Model.findByIdAndUpdate()
Model.findOneAndRemove()
Model.findByIdAndRemove()
另一种解决方案(Mongoose本身也用于own document versioning的解决方案)是使用Update Document if Current模式。