I am having issues trying to get the 'runValidators' option to work. My user schema has an email field that has required set to true but each time a new user gets added to the database (using the 'upsert' option) and the email field is empty it does not complain:
var userSchema = new mongoose.Schema({
facebookId: {type: Number, required: true},
activated: {type: Boolean, required: true, default: false},
email: {type: String, required: true}
});
findOneAndUpdate code:
model.user.user.findOneAndUpdate(
{facebookId: request.params.facebookId},
{
$setOnInsert: {
facebookId: request.params.facebookId,
email: request.payload.email,
}
},
{upsert: true,
new: true,
runValidators: true,
setDefaultsOnInsert: true
}, function (err, user) {
if (err) {
console.log(err);
return reply(boom.badRequest(authError));
}
return reply(user);
});
I have no idea what I am doing wrong, I just followed the docs: http://mongoosejs.com/docs/validation.html
In the docs is says the following:
Note that in mongoose 4.x, update validators only run on $set and $unset operations. For instance, the below update will succeed, regardless of the value of number.
I replaced the $setOnInsert with $set but had the same result.
Possible duplicate of https://github.com/Automattic/mongoose/issues/3107?
So the below script:
var assert = require('assert');
var mongoose = require('mongoose');
var Schema = mongoose.Schema;
mongoose.set('debug', true);
mongoose.connect('mongodb://localhost:27017/gh3124');
var userSchema = new mongoose.Schema({
facebookId: {type: Number, required: true},
activated: {type: Boolean, required: true, default: false},
email: {type: String, required: true}
});
var User = mongoose.model('gh3124', userSchema);
User.findOneAndUpdate(
{facebookId: 123},
{
$setOnInsert: {
facebookId: 123,
email: undefined,
}
},
{upsert: true,
'new': true,
runValidators: true,
setDefaultsOnInsert: true
}, function (err, user) {
console.log(err);
process.exit(0);
});
Gives me a validation error as expected in 4.0.6. Can you run that script locally and double check that it works for you @Jdruwe ?
This gives me the following error:
{ email:
{ [ValidatorError: Path email
is required.]
What I think is weird is the following: email is required but if I don't mention it in the setOnInsert is does not complain, if its value is undefined it does validate.
Ah yeah that's a good point. Update validators right now only run on fields that are mentioned in the update (and the query, if upsert is specified), because mongoose really has no way of knowing if the documents being updated on the server side have an email
field or not. There are definitely ways to be smarter about this, but right now update validators are somewhat limited.
I created a plugin to validate required model properties before doing update
operations in mongoose.
var mongoose = require('mongoose');
var _ = require('lodash');
var s = require('underscore.string');
function validateExtra(schema, options){
schema.methods.validateRequired = function(){
var deferred = Promise.defer();
var self = this;
try {
_.forEach(this.schema.paths, function (val, key) {
if (val.isRequired && _.isUndefined(self[key])) {
throw new Error(s.humanize(key) + ' is not set and is required');
}
});
deferred.resolve();
} catch (err){
deferred.reject(err);
}
return deferred.promise;
}
}
module.exports = validateExtra;
Must be called explicitly as a method from the model, so I recommend chaining it a .then
chain prior to the update call.
fuelOrderModel(postVars.fuelOrder).validateRequired()
.then(function(){
return fuelOrderModel.findOneAndUpdate({_id: postVars.fuelOrder.fuelOrderId}, postVars.fuelOrder,
{runValidators: true, upsert: true, setDefaultsOnInsert: true, new: true})
.then(function(doc) {
res.json({fuelOrderId: postVars.fuelOrder.fuelOrderId});
});
}, function(err){
global.saveError(err, 'server', req.user);
res.status(500).json(err);
});
@jeremyml glad that works for you :) I'd recommend only running the validation if upsert
is true, since otherwise the underlying doc may have the field already set.
so this is close but the issue still exists.
@mylastore please open a new issue and follow the issue template.
Most helpful comment
So the below script:
Gives me a validation error as expected in 4.0.6. Can you run that script locally and double check that it works for you @Jdruwe ?