Mongoose - Version Error: No matching document found for id
Asked Answered
M

7

21

Context: I have a Post Mongoose model that contains a csv_files array field to store csv strings. I make a fetch API request from a different web app to POST the csv strings for a particular Post.

The code below produces an error

UnhandledPromiseRejectionWarning: Unhandled promise rejection (rejection id: 2): VersionError: No matching document found for id "5966932399e969ad8013bedf"

router.js

router.post('/posts/:url/upload-csv/:csv_name', (req, res) => {
  let csv_name = req.params.csv_name;
  let csv_string = csv_name+req.body.csv_string;

  Post.findOne({url: req.params.url})
    .then((post) => {
      if (post.csv_files.length === 0) {
        post.csv_files.push(csv_string);
      } else {
        let foundExistingCSV = false;
        for (var i = 0; i < post.csv_files.length; i++) {
          if (post.csv_files[i].includes(csv_name)) {
            foundExistingCSV = true;
            post.csv_files[i] = csv_string;
            break;
          }
        }
        if (!foundExistingCSV) post.csv_files.push(csv_string);
      }

      post.markModified('csv_files');
      post.save();

      return res.status(200);
    })
    .catch((err) => {
      console.log(err);
      return res.status(400);
    });
});

models/post.js

const mongoose    = require('mongoose');

var stringPreset = {
  type: String,
  uppercase: true
}

var Post = mongoose.model('Post', {
  name                 : stringPreset,
  url                  : String,
  password             : String,
  csv_files            : { type : Array , "default" : [] },
  updatedAt            : { type: Date, default: Date.now }
});

module.exports = { Post };

How can I fix this so that the document saves into the csv_files array without the error?

Michaud answered 20/7, 2017 at 18:51 Comment(2)
Is it possible that multiple requests are causing the same document to get processed (almost) concurrently?Shieh
@Shieh Checking concurrent access fixed my problem, thanks! Can you write an answer?Mauriac
D
57

When saving an object to Mongo DB you have to understand that Mongo DB has a version control system in place. This helps ensure that if you save an object once, when saving it again you don't end up overwriting the previously saved data.

This is the error you're seeing. If you want to force the object to update regardless of version control in this particular instance you may want to use .update() instead. This will force the object to be updated regardless of its currently saved state.

This is because .save() watches and cares about version controls, while .update() will update the object regardless of version control.

Dor answered 20/2, 2019 at 20:54 Comment(2)
OK, this answer solved my actual question. But it brought me a new error. MongoError: Performing an update on the path '_id' would modify the immutable field '_id'Die
@Dor @Die I had an migration and also some direct queries in mongodb shell on a collection and now i have documents with different __v (some of them are 4 and some of them are 5). Now when i try to update for the first time i got this error, but in the second try it updates it successfully. And is it a good idea to remove all __vs field or update all documents to an specific version. something like this: db.collectionName.updateMany({}, { __v: 5 })Tacnaarica
G
7

I deleted version property from requests for update at body.

delete req.body.__v;

Gunpoint answered 24/6, 2020 at 7:45 Comment(0)
B
4

While it would appear a .save() is the right approach here, an .update() command would get the job done while ignoring "race conditions" that cause this error to occur. Mongo DB is throwing this error because it is concerned that I am saving an older version of the document that has already been updated:

v1 is sent to client v1 is saved, and updated to v2 in Mongo DB v1 is trying to be saved again, but Mongo DB already has v2 stored, error is thrown A better approach is to send v1 to the client and when the cart object changes, synchronize the object with the new cart object no matter what. This can be done via .update() rather than through .save().

This is because .save() watches and cares about version controls, while .update() will update the object regardless of version control.

Bedspring answered 8/10, 2021 at 12:16 Comment(0)
M
0

Looks like @robertklep was right. I fixed my issue by wrapping the first API call in a Promise and then executing the second API call after the first one completed.

I'll wait to mark this as the answer just in case anyone comes across a better solution.

Michaud answered 21/7, 2017 at 3:20 Comment(1)
I had an migration and also some direct queries in mongodb shell on a collection and now i have documents with different __v (some of them are 4 and some of them are 5). Now when i try to update for the first time i got this error, but in the second try it updates it successfully. And is it a good idea to remove all __vs field or update all documents to an specific version. something like this: db.collectionName.updateMany({}, { __v: 5 })Tacnaarica
K
0

just to comment here what my problem apparently was.

Error Message:

message: 'No matching document found for id "5c86d3a15bbcb965d85d80d1" version 3', name: 'VersionError', version: 3

My code:

update: function (data) {

        var session = new Session(data);
        database.logging("INFO", "session-update", session.cid, session.order.orderNumber);
        return new Promise(function (resolve, reject) {

            session.save()
                .then(savedSession => resolve(savedSession))
                .catch(savedSessionError => reject(savedSessionError))
        });

    }

My parameter 'data' was already a Mongoose object and I was creating a new one and trying to save() it. So like @dacopenhagen said, save() checks the version of the document and it's throwing an VersionError error.

How I fixed it Just removing the creation of the Session() object. Removed this line

var session = new Session(data);

I hope this help.

Kedron answered 11/3, 2019 at 21:48 Comment(0)
D
0

I found the problem and the possible solution here That is:

The version field is introduced by Mongoose, and is intended to protect your application from two threads / processes attempting to modify the same document, and one of them inadvertently overwriting changes by the other, as in this sequence of events:

Application A reads document 1 at {__v: 3}
Application B reads document 1 at {__v: 3}
Application B makes a change to its copy of document 1 and saves; version in the database is incremented to {__v: 4}
Application A makes a different change to its version of document 1 and attempts to save. This change is rejected because the version

fields no longer match

How this works is that, behind the scenes, mongoose’s save() method adds the original value of __v to the filter criteria in an update call, so the save() call effectively has the semantics: "Save these changes to the document if and only if the version field still has the value 3".

How you handle this may depend on your application, and what is causing what is, in effect, a race condition between two threads. For example, if you are confident that Application A is only changing a subset of fields and that no other application should be changing those fields, you can use findOneAndUpdate instead, which ignores the __v field. In most cases, you may want to have Application A retry from the beginning and hope there’s no Application C

Disobedient answered 8/7, 2024 at 19:8 Comment(0)
E
-2

I got the same error. I used findone.exec(). it worked for me

Establishment answered 11/2, 2022 at 15:3 Comment(1)
Your answer could be improved with additional supporting information. Please edit to add further details, such as citations or documentation, so that others can confirm that your answer is correct. You can find more information on how to write good answers in the help center.Laciniate

© 2022 - 2025 — McMap. All rights reserved.