我对Node.js和Mongo / Mongoose比较陌生,而且我在解决特定的Mongoose错误时遇到了非常的困难:
VersionError:找不到匹配的文档。
(此问题底部的整个错误跟踪/堆栈。)
这篇博文非常清楚地概述了如何发生VersionError:
(TL; DR - “Mongoose v3现在为每个文档添加了一个模式可配置的版本密钥。只要对数组的修改可能会更改任何数组的元素位置,该值就会以原子方式递增。”如果您尝试保存一个文档,但版本密钥不再与您检索到的对象匹配,您可以获得上述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)
答案 0 :(得分:34)
根据请求,这里是我们问题的概述,以及我们如何解决它:
在我们的系统中,我们创建了一个自定义文档锁定例程(使用redis-lock),其中以下精确(不正确)顺序发生了以下情况:
不正确的操作顺序:
一旦你看到它写出来,问题就很明显了:我们将文件保存在文件锁之外。
我们假设#6在我们的系统中需要100毫秒。这是一个100毫秒的窗口,如果有任何其他请求抓取同一个文档,我们将会有一个保存冲突(此问题中的标题错误基本上是一个保存冲突恕我直言。)
换句话说/示例:在我们的系统中,请求A抓取文档X的版本1,编辑它,然后将其解锁,但在请求A保存文档之前,请求B抓取文档X并将其增加到版本2(读取关于Mongo版本的更多信息)。然后请求A解析其客户端请求并转到保存文档X,但它正在尝试保存版本1,现在它看到它有版本2,因此上面的错误。
所以修复很简单。将您的文档保存在锁内。 (在上面的例子中,将#7移到#5之前。见下文。)
正确/固定的运营顺序
(您可以提出一个论点,即应该交换#6和#7,但这超出了Mongo / Mongoose /这个问题的范围。)
我将暂时不回答这个问题,看看是否有人可以更好地分析相关代码并解决此问题。在我们的案例中,这是一个非常系统的问题,并且当时对我们的技能水平进行故障排除非常具有挑战性。
答案 1 :(得分:10)
它可以指出与robertklep指出的同时保存同一份文件。
我们遇到了类似的问题,使用async.parallel在同一文档上运行并发保存。
答案 2 :(得分:7)
当您的进程在内存中维护过时的文档版本,然后尝试在其他进程更新文档后的某个时刻保存它时,也会发生此错误。
答案 3 :(得分:0)
我在NextJS / Express应用程序中遇到此问题,但在阅读this Mongoose discussion之后,我发现我可以通过从文档中删除__v
属性来解决问题我我试图保存:
const fixedDocument = _.pickBy(originalDocument, (val, key) => key !== '__v');
答案 4 :(得分:0)
我遇到了这个问题,因为我正在使用splice
函数从文档数组中删除一项。
我固定将mongoose中的splice
函数替换为pull
函数。
答案 5 :(得分:0)
当我尝试将用户的参考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));