使用猫鼬处理并发修改
Posted
技术标签:
【中文标题】使用猫鼬处理并发修改【英文标题】:Handling concurrent modification w/ mongoose 【发布时间】:2016-05-31 12:30:18 【问题描述】:我的应用程序中有几个地方使用了 mongoose,我需要在这些地方处理并发修改。
我知道我的所有文档中都有一个版本“__v”。我看到的大部分内容都指向这个博客:
http://aaronheckmann.tumblr.com/post/48943525537/mongoose-v3-part-1-versioning
其中概述了使用 __v 字段来防止文档中的并发数组修改。即:
posts.update( _id: postId, __v: versionNumber
, $set: 'comments.3.body': updatedText )
mongoose 是否在保存文档时以任何方式自动使用 __v 字段来验证文档?还是您总是必须将其添加到您的查询语句中?
【问题讨论】:
mongoose.set("debug",true)
会为您解答您的问题。并不是说我无论如何都喜欢这个过程。测试__v
的特定值意味着您已经从文档中获得了该信息,并且如果该值/版本不同,您根本无法修改内容。这几乎是不现实的,实际上您的应用程序不应该关心这一点,或者应该以不同的方式应用更新,其中需要“历史”之类的东西。即添加到数组。如果您设计了正确的访问模式,那么您将不会遇到此类问题。
上述代码中的快速示例。你应该从不写comments.3.body
暗示更新数组中那个索引位置的“body”。相反,您应该写.update( "_id": postId, "comments._id": commentId , "$set": "comments.$.body": updatedText )
。这样一来,除了您知道自己真正想要的元素之外,您永远不会更新任何东西,而不是现在可能处于该位置的其他东西。 __v
唯一能帮助的就是避免两个用户同时更改相同的评论。但最好只允许作者进行更改。
【参考方案1】:
查看Mongoose
源代码,__v
确实只用于arrays
,VERSION_WHERE
是在updating the array path时设置的。
if ('$push' == op || '$pushAll' == op || '$addToSet' == op)
self.$__.version = VERSION_INC;
// now handling $set, $unset
else if (/\.\d+\.|\.\d+$/.test(data.path))
// subpath of array
self.$__.version = VERSION_WHERE;
根据this answer,
var t = Test(); t.name = 'hi' t.arr = [1, 2, 3, 4, 5, 6]; t.save(function (err, result) console.log(result); // use Mongoose pull method on the array t.arr.pull(3); t.save(function(err2, result2) console.log(result2) ); );
结果:
__v: 0, name: 'hi', _id: 53f59d2a6522edb12114b98c, arr: [ 1, 2, 3, 4, 5, 6 ] __v: 1, name: 'hi', _id: 53f59d2a6522edb12114b98c, arr: [ 1, 2, 4, 5, 6 ]
【讨论】:
以上是关于使用猫鼬处理并发修改的主要内容,如果未能解决你的问题,请参考以下文章
在 Grails (GORM) 中处理并发修改,同时避免过时对象异常