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.

Answers:

Answer

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) { ...
Answer

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.

Tags

Recent Questions

Top Questions

Home Tags Terms of Service Privacy Policy DMCA Contact Us

©2020 All rights reserved.