Perhaps it's the time, perhaps it's me drowning in sparse documentation and not being able to wrap my head around the concept of updating in Mongoose :)
Here's the deal:
I have a contact schema and model (shortened properties):
var mongoose = require('mongoose'), Schema = mongoose.Schema; var mongooseTypes = require("mongoose-types"), useTimestamps = mongooseTypes.useTimestamps; var ContactSchema = new Schema({ phone: { type: String, index: { unique: true, dropDups: true } }, status: { type: String, lowercase: true, trim: true, default: 'on' } }); ContactSchema.plugin(useTimestamps); var Contact = mongoose.model('Contact', ContactSchema);
I receive a request from the client, containing the fields I need and use my model thusly:
mongoose.connect(connectionString); var contact = new Contact({ phone: request.phone, status: request.status });
And now we reach the problem:
contact.save(function(err){...})
I'll receive an error if the contact with the same phone number already exists (as expected - unique)update()
on contact, since that method does not exist on a documentContact.update({phone:request.phone}, contact, {upsert: true}, function(err{...})
{status: request.status, phone: request.phone ...}
it works - but then I have no reference to the specific contact and cannot find out its createdAt
and updatedAt
properties.So the bottom line, after all I tried: given a document contact
, how do I update it if it exists, or add it if it doesn't?
Thanks for your time.
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.
Upsert. Using the upsert option, you can use findOneAndUpdate() as a find-and-upsert operation. An upsert behaves like a normal findOneAndUpdate() if it finds a document that matches filter . But, if no document matches filter , MongoDB will insert one by combining filter and update as shown below.
Overview. Upsert is a combination of insert and update (inSERT + UPdate = upsert). We can use the upsert with different update methods, i.e., update, findAndModify, and replaceOne. Here in MongoDB, the upsert option is a Boolean value.
Updating Using QueriesThe save() function is generally the right way to update a document with Mongoose. With save() , you get full validation and middleware. For cases when save() isn't flexible enough, Mongoose lets you create your own MongoDB updates with casting, middleware, and limited validation.
Mongoose now supports this natively with findOneAndUpdate (calls MongoDB findAndModify).
The upsert = true option creates the object if it doesn't exist. defaults to false.
var query = {'username': req.user.username}; req.newData.username = req.user.username; MyModel.findOneAndUpdate(query, req.newData, {upsert: true}, function(err, doc) { if (err) return res.send(500, {error: err}); return res.send('Succesfully saved.'); });
In older versions Mongoose does not support these hooks with this method:
I just burned a solid 3 hours trying to solve the same problem. Specifically, I wanted to "replace" the entire document if it exists, or insert it otherwise. Here's the solution:
var contact = new Contact({ phone: request.phone, status: request.status }); // Convert the Model instance to a simple object using Model's 'toObject' function // to prevent weirdness like infinite looping... var upsertData = contact.toObject(); // Delete the _id property, otherwise Mongo will return a "Mod on _id not allowed" error delete upsertData._id; // Do the upsert, which works like this: If no Contact document exists with // _id = contact.id, then create a new doc using upsertData. // Otherwise, update the existing doc with upsertData Contact.update({_id: contact.id}, upsertData, {upsert: true}, function(err{...});
I created an issue on the Mongoose project page requesting that info about this be added to the docs.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With