Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to know if Mongoose's upsert created a new document?

I have this code in node.js/express.js:

var User = mongoose.model('User');
var usersRouter = express.Router();
usersRouter.put('/:id', function(req, res) {
    req.body._id = req.params.id;
    var usr = new User(req.body);

    usr.validate(function (err) {
        if (err) {
            res.status(400).json({});
            return;
        }

        var upsertData = usr.toObject();
        delete upsertData._id;

        User.update({_id: usr._id}, upsertData, {upsert: true}, function(err) {
            if (err) {
                res.status(500).json({});
                return;
            }

            res.status(204).json({});
        });
    });
});

It works fine, but I would like to send a different response to the client if a new document has been created (status 201 with json in response body) or an existing one has been updated (status 204).

Is there a way to tell the difference from the callback of User.update?

like image 614
hornobster Avatar asked Oct 27 '14 16:10

hornobster


People also ask

How does the Upsert option work?

Or in other words, upsert is a combination of update and insert (update + insert = upsert). If the value of this option is set to true and the document or documents found that match the specified query, then the update operation will update the matched document or documents.

What is Upsert true in mongoose?

In MongoDB, an upsert means an update that inserts a new document if no document matches the filter . To upsert a document in Mongoose, you should set the upsert option to the Model.

What is the difference between updateOne and findOneAndUpdate?

findOneAndUpdate returns a document whereas updateOne does not (it just returns the _id if it has created a new document).

What does findOneAndUpdate return?

As the name implies, findOneAndUpdate() finds the first document that matches a given filter , applies an update , and returns the document. By default, findOneAndUpdate() returns the document as it was before update was applied. You should set the new option to true to return the document after update was applied.


1 Answers

Use the third parameter from callback function:

...
User.update({_id: usr._id}, upsertData, {upsert: true}, function(err, num, n) {
  if (err) {
     res.status(500).json({});
     return;
   }

   if (!n.updatedExisting) { 
       /* new document */
   }

   res.status(204).json({});
});
...

n is an object like this:

{ updatedExisting: false,
  upserted: <ObjectId>,
  n: 1,
  connectionId: 11,
  err: null,
  ok: 1 }

updatedExisting property is true when a document was updated -- so it was created before. If it's false, then it means that the new document was created during this call.

like image 82
Ionică Bizău Avatar answered Oct 12 '22 13:10

Ionică Bizău