Node.js / Mongoose上的“VersionError:找不到匹配的文档”错误
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Node.js / Mongoose上的“VersionError:找不到匹配的文档”错误相关的知识,希望对你有一定的参考价值。
我对Node.js和Mongo / Mongoose比较陌生,而且我在解决特定的Mongoose错误时非常困难:
VersionError:找不到匹配的文档。
(此问题底部的整个错误跟踪/堆栈。)
这篇博文非常清楚地概述了如何发生VersionError:
(TL; DR - “Mongoose v3现在为每个文档添加一个模式可配置的版本密钥。只要对数组的修改可能会更改任何数组的元素位置,该值就会以原子方式递增。”如果您尝试保存文档,但版本key不再匹配您检索到的对象,您将获得上面的VersionError
。)
核心问题:有没有办法显示有问题的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在我们的系统中需要100毫秒。这是一个100毫秒的窗口,如果有任何其他请求抓取同一个文档,我们将会有一个保存冲突(此问题中的标题错误基本上是一个保存冲突恕我直言)。
换句话说/示例:在我们的系统中,请求A抓取文档X的版本1,编辑它,然后将其解锁,但在请求A保存文档之前,请求B抓取文档X并将其增加到版本2(在Mongo上阅读有关此内容的更多信息的版本)。然后请求A解析其客户端请求并转到保存文档X,但它正在尝试保存版本1,现在它看到它有版本2,因此上面的错误。
所以修复很简单。将您的文档保存在锁内。 (在上面的例子中,将#7移到#5之前。见下文。)
正确/固定的运营顺序
- 收到客户请求
- 文件被锁定
- 检索文件
- 文件已编辑
- 文件已保存
- 文件已解锁
- 客户请求已解决
(您可以提出一个论点,即应该交换#6和#7,但这超出了Mongo / Mongoose /这个问题的范围。)
我暂时不回答这个问题,看看是否有人能够更好地分析相关代码并解决这个问题。在我们的案例中,这是一个非常系统的问题,并且对于我们当时的技能水平进行故障排除非常具有挑战性。
它可能指向与robert klep指出的同时保存相同的文档。
我们有一个类似的问题,使用async.parallel在同一文档上运行并发保存。
当您的进程在内存中维护过时的文档版本然后尝试在其他进程更新后的某个时刻保存它时,也会发生此错误。
当我尝试将用户的参考ID更新为电子邮件时,我遇到了同样的错误。使用async / await修复非常简单!这里的代码片段,希望它有所帮助。
email
.save()
.then(() =>
User.findById(email.from).then(async sender => { // declare function as async
sender.emails.sent.push(email._id);
await sender.save(); // wait for save() to complete before proceeding
}).catch((err) => console.log(err))
)
.then(() =>
User.findById(email.to).then(async receiver => { // same as above
receiver.emails.received.push(email._id);
await receiver.save(); // same as above
}).catch((err) => console.log(err))
)
.then(() => res.status(200).json({ message: successMessage }))
.catch(err => console.log(err));
我在NextJS / Express应用程序中遇到了这个问题,但在阅读this Mongoose discussion之后,我发现我可以通过从我试图保存的文档中删除__v
属性来解决问题:
const fixedDocument = _.pickBy(originalDocument, (val, key) => key !== '__v');
我有这个问题因为我使用splice
函数从Document数组中删除了一个项目。
我用splice
用pull
函数修复了替换mongoose函数。
以上是关于Node.js / Mongoose上的“VersionError:找不到匹配的文档”错误的主要内容,如果未能解决你的问题,请参考以下文章
Heroku 上的 Node.js Express 应用程序不会使用 Mongoose 连接到 MongoLab 数据库
模型与架构上的 Node.js 和 mongoose module.exports