Jesse Earle
Jesse Earle

Reputation: 1632

How do I merge update a document using mongoose.js?

I have a model with schema:

schema = new Schema({
    name: String,
    sections: [{
        name: String,
        columns: [{
            name: String      
        }]
    }]
}];

//Lets call the model a Page

For simplicity, I retrieve the entire model:

app.get('/page/:name', function(req, res){
    Page.findOne( {name: req.params.name}, function(err, page){
        //error handling
        res.send page
    });
});

With request GET /page/myPage I receive:

{
    //_id, __v, etc..
    name: 'myPage',
    sections: [{
        name: 'Section 1',
        columns [{
            name: 'My #1 Column'
        }]
    }]
}

I change the column 0 name to My #1 Column FOOBAR! in the client

{
    //_id, __v, etc..
    name: 'myPage',
    sections: [{
        name: 'Section 1',
        columns [{
            name: 'My #1 Column FOOBAR!'
        }]
    }]
}

Another user adds a column with name: 'My #2 Column!!!'

   {
        //_id, __v, etc..
        name: 'myPage',
        sections: [{
            name: 'Section 1',
            columns [{
                name: 'My #1 Column'
            },
            {
                name: 'My #2 Column!!!'
            }]
        }]
    }

Both users POST the entire out of sync JSON to the server. I want to merge them.

Here is my current save method:

app.post('/page/save', function(req, res) {
  var newPage = req.body.page;

  Page.findOne({
    _id: newPage._id
  }, function(err, page) {
    if (err) {
      return res.send(err);
    }

    // this portion is obviously problematic as it doesn't merge the objects
    // it simply overwrites it with whatever page JSON you received at the time
    // of the request.
    page.sections = newPage.sections;

    page.save(function(err) {
      if (err) {
        res.send(err);
      } else {
        res.send('success!');
      }
    });

  });
});

Do I need to create my own update queue, that first retrieves the latest document from the server, merges the documents together and then saves them. Or is this handled by mongodb.

Also, is there a simple method like update, that will merge the old object with the new object, and save?

Thank you.

Upvotes: 5

Views: 9760

Answers (2)

Beldar
Beldar

Reputation: 481

I do it like this:

.put('/:pr_id', (req, res, next) => {
      let pr_id = req.params.pr_id;


      PR.findById(pr_id, (err, doc) => {
        if (err) {
          return res.status(500).json({error: err});
        }
        if (!doc){
          return res.status(404).json({error: 'Document not found'});
        }

        let updated = req.body.pr;
        Object.assign(doc, updated);

        doc.save((err) => {
          if (err) {
            return res.status(500).json({error: err});
          }

          res.json(doc);
        });
      });

Object.assign basically merges both objects ( https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Global_Objects/Object/assign )

Upvotes: 7

Pier-Luc Gendreau
Pier-Luc Gendreau

Reputation: 13814

_.merge method can be used with a caveat: you can't merge a mongoose document, it has to be a plain object either found with .lean() or converted with .toObject()

Model.update({
  _id: doc._id
}, {
  $set: _.merge(doc.toObject(), {
    stuff: {
      hello: 'world'
    }
  })
})

Upvotes: -1

Related Questions