/home

Insert-or-Update with MongoDB and Mongoose

A very common pattern in databases is inserting a new entry or updating an existing entry when a certain criteria matches. How to achieve this depends on the database engine you are using. In MySQL and some other database solutions, for example, you can use the INSERT [...] ON DUPLICATE KEY UPDATE [...] pattern. And for MongoDB, there is the upsert parameter that can be used in several methods, for example in the update() method.

When working with MongoDB and Mongoose (which is a MongoDB ORM for Node.js), implementing the insert-or-update is pretty straightforward. There are some quirks, though. The following example uses the findOneAndUpdate() method of Mongoose (also see the documentation on findOneAndUpdate() of MongoDB) which by default only finds and updates documents. By supplying the options parameter, you can change that, though.

var modelDoc = new MyModel({ foo: 'bar' });

MyModel.findOneAndUpdate(
    {foo: 'bar'}, // find a document with that filter
    modelDoc, // document to insert when nothing was found
    {upsert: true, new: true, runValidators: true}, // options
    function (err, doc) { // callback
        if (err) {
            // handle error
        } else {
            // handle document
        }
    }
);

The options parameter is essential to make the insert work.

  • By setting upsert: true, you command MongoDB to actually add the modelDoc document to the collection if no result was found by the {foo: 'bar'} filter.
  • The new: true option changes what is returned in the callback function. If it is false, doc will contain the document before updating (or null before inserting). If it is true, doc contains the document after updating or creating. While false is the default option, I guess most people would actually prefer it to be true.
  • The runValidators: true option must be set if you want Mongoose to run the validators. By default, these will not be executed when using findOneAndUpdate().