Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How do I update/upsert a document in Mongoose?

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:

  1. If I call contact.save(function(err){...}) I'll receive an error if the contact with the same phone number already exists (as expected - unique)
  2. I can't call update() on contact, since that method does not exist on a document
  3. If I call update on the model:
    Contact.update({phone:request.phone}, contact, {upsert: true}, function(err{...})
    I get into an infinite loop of some sorts, since the Mongoose update implementation clearly doesn't want an object as the second parameter.
  4. If I do the same, but in the second parameter I pass an associative array of the request properties {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.

like image 328
Traveling Tech Guy Avatar asked Sep 01 '11 07:09

Traveling Tech Guy


People also ask

How do you update Upsert?

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.

How do you Upsert a Mongoose?

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.

What is the difference between update and Upsert in MongoDB?

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.

How do you update a Mongoose?

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.


2 Answers

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:

  • defaults
  • setters
  • validators
  • middleware
like image 140
Pascalius Avatar answered Oct 06 '22 11:10

Pascalius


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.

like image 25
Clint Harris Avatar answered Oct 06 '22 10:10

Clint Harris