Skip to content

Instantly share code, notes, and snippets.

@d1manson
Created September 28, 2017 10:20
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save d1manson/a36c18ae5c77a2a141b902e7c614bc62 to your computer and use it in GitHub Desktop.
Save d1manson/a36c18ae5c77a2a141b902e7c614bc62 to your computer and use it in GitHub Desktop.
Unlike findOneAndUpdate, this returns both the old and the new docs, the operation is performed atomically
/*
Unlike findOneAndUpdate, this returns both the old and the new docs,
the operation is performed atomically.
Note that although it can apply defaults properly, it does not apply
pre-update hooks, with the exception of timestamps (see note in code).
Example:
Dogs.upsert({owner: 'wallace', name: 'grommit'}, {breakfast: 'eggs'})
.then(res => console.dir({'old': res.oldDoc, 'new': res.newDoc}));
*/
module.exports = function UpsertPlugin(schema){
schema.statics.upsert = function(query, update){
update = update.$set || update;
let preemptiveData = (new this(query)).toJSON();
Object.keys(update).forEach(k => delete preemptiveData[k]); // need fields to be unique for $set/$setOnInsert
return this.findOneAndUpdate(query, {
$set: update,
$setOnInsert: preemptiveData
}, {
upsert: true,
new: false,
setDefaultsOnInsert: false // we have explicitly dealt with this above
}).then(oldDoc => {
// Deal with timestamps on the collection - this is rather hacky and
// actually means the values stored will be ever so slightly earlier
// than the values returned to the caller of this function.
let timestamps = schema.options.timestamps;
if(timestamps && timestamps.updatedAt){
update[timestamps.updatedAt] = Date.now();
}
if(!oldDoc && timestamps && timestamps.createdAt){
update[timestamps.createdAt] = Date.now();
}
let newDoc = new this(Object.assign(oldDoc ? oldDoc.toJSON() : preemptiveData, update));
newDoc.isNew = false; // we have upserted it!!!
return {
oldDoc,
newDoc: newDoc
};
});
};
};
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment