Node.js / Mongoose上的“VersionError:没有find匹配的文档”错误
我对Node.js和Mongo / Mongoose比较陌生,在解决特定的Mongoose错误时遇到了一些困难:
VersionError:未find匹配的文档。
(整个错误跟踪/堆栈在这个问题的底部。)
这个博客文章非常清楚地概述了一个VersionError可能发生的情况:
- http://aaronheckmann.blogspot.com/2012/06/mongoose-v3-part-1-versioning.html
(TL; DR – “Mongoose v3现在为每个文档添加了一个模式可configuration的版本密钥,只要对数组的修改可能改变任何数组元素的位置,该值就会自动递增。”如果试图保存文档,键不再匹配你检索到的对象,你会得到上面的VersionError
。)
核心问题:有没有办法显示有问题的save()
操作? 或者哪个文件没有保存? 还是什么呢 ?! ;)
挑战:这是一个相对较大的有许多arrays的代码库,我不确定如何开始解决这个问题。 特别是,错误跟踪/堆栈似乎并不显示问题存在的地方。 见下文:
VersionError: No matching document found. at handleSave (<project_path>/node_modules/mongoose/lib/model.js:121:23) at exports.tick (<project_path>/node_modules/mongoose/lib/utils.js:408:16) at null.<anonymous> (<project_path>/node_modules/mongoose/node_modules/mongodb/lib/mongodb/collection.js:484:9) at g (events.js:192:14) at EventEmitter.emit (events.js:126:20) at Server.Base._callHandler (<project_path>/node_modules/mongoose/node_modules/mongodb/lib/mongodb/connection/base.js:391:25) at Server.connect.connectionPool.on.server._serverState (<project_path>/node_modules/mongoose/node_modules/mongodb/lib/mongodb/connection/server.js:558:20) at MongoReply.parseBody (<project_path>/node_modules/mongoose/node_modules/mongodb/lib/mongodb/responses/mongo_reply.js:131:5) at Server.connect.connectionPool.on.server._serverState (<project_path>/node_modules/mongoose/node_modules/mongodb/lib/mongodb/connection/server.js:517:22) at EventEmitter.emit (events.js:96:17)
根据要求,以下是我们问题的概要,以及我们如何解决问题:
在我们的系统中,我们创build了一个自定义的文档locking例程(使用redis-lock),其中以下精确(不正确)的顺序发生:
错误的操作顺序:
- 收到客户请求
- 文档被locking
- 检索到文档
- 文件编辑
- 文件解锁
- 客户端请求解决
- 保存文件
一旦你看到它写出来,问题是显而易见的:我们正在我们的文件保存在文档锁外。
假设#6在我们的系统中需要100ms。 这是一个100毫秒的窗口,其中如果有其他请求抓取相同的文档,我们将有一个保存冲突(这个问题的标题错误基本上是一个保存冲突恕我直言)。
换句话说,例如:在我们的系统中,请求A获取了文档X的版本1,编辑了它,然后解锁了它,但是在请求A保存了文档之前,请求B抓取了文档X并将其增加到版本2(在Mongo版本更多关于这方面的信息)。 然后,请求Aparsing其客户端请求,并保存文档X,但它试图保存版本1,现在它看到它有版本2,从而上面的错误。
所以修复很简单 将你的文档保存在你的锁里。 (在上面的例子中,把#7移到#5之前,见下面)
正确的/固定的操作顺序
- 收到客户请求
- 文档被locking
- 检索到文档
- 文件编辑
- 保存文件
- 文件解锁
- 客户端请求解决
(你可以把#6和#7换成一个参数,但这不在Mongo / Mongoose /这个问题的范围之内。)
我将暂时搁置这个问题一段时间,看看是否有人可以更好地隔离相关代码并解决这个问题。 在我们的案例中,这是一个非常系统的问题,对于我们当时的技能水平进行故障排除非常具有挑战性。
它可以指出同时保存同样的文件robertklep指出。
我们有一个类似的问题,使用async.parallel在同一个文档上运行并发保存。
当您的进程在内存中维护文档的过时版本,然后尝试在由另一个进程更新后的某个点上保存它时,也会发生此错误。