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.
However, the update() function does not return the updated document but returns a write result.
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.
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.
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.
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) { ...
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.
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