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),其中以下精确(不正确)的顺序发生:

错误的操作顺序:

  1. 收到客户请求
  2. 文档被locking
  3. 检索到文档
  4. 文件编辑
  5. 文件解锁
  6. 客户端请求解决
  7. 保存文件

一旦你看到它写出来,问题是显而易见的:我们正在我们的文件保存在文档锁外。

假设#6在我们的系统中需要100ms。 这是一个100毫秒的窗口,其中如果有其他请求抓取相同的文档,我们将有一个保存冲突(这个问题的标题错误基本上是一个保存冲突恕我直言)。

换句话说,例如:在我们的系统中,请求A获取了文档X的版本1,编辑了它,然后解锁了它,但是在请求A保存了文档之前,请求B抓取了文档X并将其增加到版本2(在Mongo版本更多关于这方面的信息)。 然后,请求Aparsing其客户端请求,并保存文档X,但它试图保存版本1,现在它看到它有版本2,从而上面的错误。

所以修复很简单 将你的文档保存在你的锁里。 (在上面的例子中,把#7移到#5之前,见下面)

正确的/固定的操作顺序

  1. 收到客户请求
  2. 文档被locking
  3. 检索到文档
  4. 文件编辑
  5. 保存文件
  6. 文件解锁
  7. 客户端请求解决

(你可以把#6和#7换成一个参数,但这不在Mongo / Mongoose /这个问题的范围之内。)

我将暂时搁置这个问题一段时间,看看是否有人可以更好地隔离相关代码并解决这个问题。 在我们的案例中,这是一个非常系统的问题,对于我们当时的技能水平进行故障排除非常具有挑战性。

它可以指出同时保存同样的文件robertklep指出。

我们有一个类似的问题,使用async.parallel在同一个文档上运行并发保存。

当您的进程在内存中维护文档的过时版本,然后尝试在由另一个进程更新后的某个点上保存它时,也会发生此错误。