我对Node.js和Mongo / Mongoose相对较新,并且在排查特定Mongoose错误时遇到了 非常 困难的时间:
VersionError:找不到匹配的文档。
(此问题底部的整个错误跟踪/堆栈。)
这篇博客非常清楚地概述了VersionError可能如何发生:
(TL; DR-“ Mongoose v3现在向每个文档添加了可配置模式的版本密钥。只要对数组的修改有可能更改任何数组元素的位置,此值都会自动增加。”如果您尝试保存文档,但是版本键不再与您检索到的对象匹配,您将获得上述内容VersionError。)
VersionError
核心问题: 有什么方法可以显示违规save()操作?还是哪个文档保存失败?还是 什么 ?;)
save()
挑战: 这是一个包含许多数组的相对较大的代码库,我不确定如何开始对问题进行故障排除。特别是,错误跟踪/堆栈似乎无法显示问题所在。见下文:
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)
根据请求,以下是我们的问题及其解决方案的概述:
在我们的系统中,我们创建了一个自定义文档锁定例程(使用redis-lock),其中以下操作以这种精确(不正确)的顺序发生:
操作顺序不正确:
一旦看到它写出来,问题就很明显了:我们将文档保存在文档锁之外。
假设#6在我们的系统中花费了100ms。这是一个100毫秒的窗口,如果任何其他请求都抓住了该文档,我们将发生保存冲突(此问题中的标题错误基本上是保存冲突恕我直言)。
换句话说,在我们的系统中,请求A抓取了文档X的版本1,对其进行了编辑,然后将其解锁,但是在请求A保存该文档之前,请求B抓取了文档X并将其递增到版本2(在Mongo上阅读)有关更多信息的版本)。然后,请求A解析其客户请求并保存文档X,但它正在尝试保存版本1,现在它看到它具有版本2,因此出现上述错误。
因此修复很容易。将文档保存在锁中。(在上面的示例中,将#7移至#5之前。请参见下文。)
正确/固定的操作顺序
(您可以争辩说应该交换#6和#7,但这不在Mongo / Mongoose /这个问题的范围内。)
我将暂时搁置这个问题,看看是否有人可以找到更好的方法来隔离相关代码并解决此问题。在我们的案例中,这是一个非常系统的问题,非常难以解决当时的技术水平。