Romulo Sousa
Romulo Sousa

Reputation: 95

Why mongoose is changing the _id when I use its findOneAndUpdate method?

I came from relational database whereas the primary key (this case, _id) is the same along its life, and so I was surprised when I saw this behavior in mongodb.

I'm using the mongoose's findOneAndUpdate plugin method in the below way:

User.findOneAndUpdate(
  { "products._id": _id, "_id": req.payload._id },
  {
    $set: {
      "products.$": { name: "New name" },
    },
  },
  {
    new: true,
    runValidators: true,
  },
  function (err, doc) {
    if (err != null) {
      res
        .status(500)
        .json({
          message: "Error on updating. Please, try again later.",
        });
    } else if (doc == null) {
      res.status(404).json({ message: "Product not found." });
    } else {
      res.status(200).json(doc.products);
    }
  }
);

Before start:

{_id: 58b5e637f9f904a800721abf, name: "Old name"}

After (_id changed):

{_id: 58b5e35a7f4ff38c433a5bc9, name: "New name"}

I just want to keep the same _id after an update, 'cause I think I could to face troubles when I implement a simultaneous updates for example.

I searched and I found out this mongoose method is called straightforward to the mongo's drivers without middlewares. Thus, I guess this question can be solved by experts in mongodb without knowledge in mongoose.

Upvotes: 5

Views: 2180

Answers (2)

Buzz Moschetti
Buzz Moschetti

Reputation: 7588

Whatever is happening is local to your mongoose space. Under no circumstances will mongodb findOneAndUpdate() change the _id of a matching document but if upsert:true it might create a new _id

Upvotes: 0

NodeNodeNode
NodeNodeNode

Reputation: 753

_id is attached to a document revision, not a document entity.

By passing new: true you're asking Mongo to return the id of the latest revision, which will have a different id than the original document (Upsert).

For document based storages it's recommended to implement your own UUID schema.

Either go deterministic with uuid:

var UUID = require('uuid-1345');

UUID.v3({
  namespace: UUID.namespace.oid,
  name: "abc" // Some formula to calculate you uuid, could be based on the document's legacy id or some other unique identifier.
}, function (err, id) {
  console.log("Generated a name-based UUID using MD5:\n\t%s\n", id);
});

Or random with plain random HEX:

var crypto = require('crypto');

var id = crypto.randomBytes(20).toString('hex');

Include this in your document's body... and don't forget to index it!

Upvotes: 5

Related Questions