Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Unable to update mongoose model

I have a weird issue that is baffling me. I have a model:

var Model = new Schema({
    name: String,
    variations: Array
});

The variations entry looks like this:

[ {code: '', price: '' }, {code: '', price: '' }]

I need to add a new field - say "color". So I am doing this to batch update:

Model.find().exec(function(err, products) {
    if (!err) {
        products.forEach(function(p) {
            for(var i = p.variations.length - 1; i >= 0; i--) {
                p.variations[i]['color'] = 'red';
                // This shows all existing variations 
                // with the new color feed - correct
                console.log(p.variations[i]);
            }
            p.save(function(err) {
                if (!err) {
                    console.log("Success");
                } else {
                    console.log(err);
                }
            });
        });     
    }
});

However the "color" field is not set - if I go through again and comment out the p.variations[i]['color'] = 'red'; line then it does not show. I can't seem to figure out why it's doing this. I have an onSave event that is triggered correctly so it's saving. I also do not have any check on the variations structure - i.e. there is no code that only allows code and price. I'm obviously missing something but after a couple of hours I ran out of ideas.

like image 299
cyberwombat Avatar asked Feb 25 '13 20:02

cyberwombat


People also ask

What is update return Mongoose?

However, the update() function does not return the updated document but returns a write result.

What is the difference between schema and model in Mongoose?

A Mongoose schema defines the structure of the document, default values, validators, etc., whereas a Mongoose model provides an interface to the database for creating, querying, updating, deleting records, etc.

What is Upsert Mongoose?

In MongoDB, an upsert is an update query that inserts a new document if no document matches the given filter. To upsert a document in Mongoose, you need to set the upsert option to true in updateOne() method as shown below: const mongoose = require('mongoose') const User = mongoose.

What does save () do in Mongoose?

save() is a method on a Mongoose document. The save() method is asynchronous, so it returns a promise that you can await on. When you create an instance of a Mongoose model using new, calling save() makes Mongoose insert a new document.


2 Answers

When you modify the contents of an untyped Array field like variations, you need to notify Mongoose that you've changed its value by calling markModified(path) on the modified document or a subsequent save() call won't save it. See docs.

  for(var i = p.variations.length - 1; i >=0; i--) {
    p.variations[i]['color'] = 'red';
  }
  p.markModified('variations');
  p.save(function(err) { ...
like image 153
JohnnyHK Avatar answered Sep 30 '22 16:09

JohnnyHK


You have to use the set function to change a property. The reasoning behind that is that mongoose has to mark the field as modified in order to be saved to the database.

for(var i = p.variations.length - 1; i >=0; i--) {
  p.variations[i].set({"color":"red", "code":"herr"});
  // or
  p.variations[i].set("color":"red");
  p.variations[i].set("code":"herr");
}

An alternative would be to change the field's value the old way, without going trought the setter, then manually mark it as modified: p.markModified('variations');

In my opinion you should always use the setter since this is more readable. You can just pass a json object containing all your changes in parameter and it will safely update the fields that you really want to change.

like image 25
Jean-Philippe Leclerc Avatar answered Sep 30 '22 17:09

Jean-Philippe Leclerc