简体   繁体   中英

“VersionError: No matching document found” error on Node.js/Mongoose

I'm relatively new to Node.js and Mongo/Mongoose, and I'm having a very difficult time troubleshooting a specific Mongoose error:

VersionError: No matching document found.

(Entire error trace/stack at the bottom of this question.)

This blog post pretty clearly outline how a VersionError might occur:

(TL;DR - "Mongoose v3 now adds a schema-configurable version key to each document. This value is atomically incremented whenever a modification to an array potentially changes any array's elements position." If you try to save a document, but the version key no longer matches the object you have retrieved, you get the above VersionError .)

Core Question: Is there some way to display the offending save() operation? Or which document failed to save? Or anything at all?! ;)

The Challenge: this is a relatively large code base with many arrays, and I am unsure how to begin to troubleshoot the problem. In particular, the error trace/stack does NOT seem to show where the problem exists. See below:

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)

Per request, here is an outline of our problem, and how we resolved it:

In our system we created a custom Document locking routine (using redis-lock), wherein the following happened in this precise (incorrect) order:

INCORRECT ORDER OF OPERATIONS:

  1. Client request received
  2. Document locked
  3. Document retrieved
  4. Document edited
  5. Document unlocked
  6. Client request resolved
  7. Document saved

Once you see it written out, the problem is obvious: we were saving our Documents outside our Document lock.

Let's assume #6 takes 100ms in our system. That is a 100ms window wherein if any other requests grabs that same Document, we're going to have a save conflict (the titled error in this Question is basically a save conflict IMHO).

In other words/example: in our system, Request A grabbed Version 1 of Document X, edited it, then unlocked it, but before Request A saved the Document, Request B grabbed Document X and incremented it to Version 2 (read up on Mongo versions for more info about this). Then Request A resolves its Client request and goes to save Document X, but it's trying to save Version 1, and now it sees it has Version 2, and thus the error above.

So the fix is easy. Save your Documents inside your lock. (In the above example, move #7 to before #5. See below.)

CORRECT/FIXED ORDER OF OPERATIONS

  1. Client request received
  2. Document locked
  3. Document retrieved
  4. Document edited
  5. Document saved
  6. Document unlocked
  7. Client request resolved

(You could make an argument that #6 and #7 should be swapped, but that is outside the scope of Mongo/Mongoose/this question.)

I am going to leave this question un-answered for a while and see if anyone can shed some light on a better way to isolate the relevant code and troubleshoot this issue. In our case, this was a very systemic problem and VERY challenging to troubleshoot for our skill level at the time.

It propably points to saving the same document concurrently as robertklep points out.

We had a similar issue running concurrent saves on the same document using async.parallel.

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

I had the same error when i tried to update a user's reference IDs to an email. The fix was really simple with async / await! Here the code snippet, hope it helps.

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应用程序中遇到了这个问题,但在阅读了Mongoose的讨论之后,我发现我可以通过从我试图保存的文档中删除__v属性来解决问题:

const fixedDocument = _.pickBy(originalDocument, (val, key) => key !== '__v');

I had this issue because I was removing an item from an array of a Document using splice function.

I fixed replacing splice function with pull function from mongoose .

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM