I have the following schema
var Schema = new mongoose.Schema({
type: {required: true, type: String, enum: ["device", "beacon"], index: true},
device: {
type: {type: String},
version: {type: String},
model: {type: String}
},
name: String,
beaconId: {required: false, type: mongoose.Schema.Types.ObjectId},
lastMeasuredTimestamp: {type: Number, index: true},
lastMeasuredPosition: {type: [Number], index: "2dsphere"},
lastMeasuredFloor: {type: Number, index: true}
}, {strict: false});
Note that I have set strict to false. This is because it is valid to add custom properties not defined in the schema to the document.
Next I do the following query
DB.Document.update({_id: "SOME_ID_HERE"}, {$set: {type: "bull"}}, {runValidators: true})
This will change the property 'type' to a value which is invalid according to the Mongoose schema. I use the runValidators option to ensure that the schema validation is run.
The end result of this query however is that 'type' is changed to 'bull' and no validation is run. When I set strict to true however the validation does run and an error is (correctly) shown.
Why does strict influence whether or no the validation runs? When I look at this description http://mongoosejs.com/docs/guide.html#strict it only mentions that strict limits adding properties not defined in the schema (something I do not want for this specific schema).
Install info:
After some trying out I figured out a solution that did work. I post it here should any future Mongoose users run into this same problem.
The trick is to use the save
method on a Mongoose document. For some reason this does run the validators properly while also allowing the use of the strict option.
So the basic process for updating a document would look like this:
Model.findOne
save
on the document. In code:
// Find the document you want to update
Model.findOne({name: "Me"}, function(error, document) {
if(document) {
// Merge the document with the updates values
merge(document, newValues);
document.save(function(saveError) {
// Whatever you want to do after the update
});
}
else {
// Mongoose error or document not found....
}
});
// Merges to objects and writes the result to the destination object.
function merge(destination, source) {
for(var key in source) {
var to = destination[key];
var from = source[key];
if(typeof(to) == "object" && typeof(from) == "object")
deepMerge(to, from);
else if(destination[key] == undefined && destination.set)
destination.set(key, from);
else
destination[key] = from;
}
}