Until I discovered runValidators recently, I had always assumed mongoose did validation on updates by default. But it doesn't!
Would it be possible to add a global config or a schema config that would make runValidators
default to true
for all updates? (We could then override with false
on individual queries, if we need to.)
The documentation says:
Be careful: update validators are off by default because they have several caveats.
And the caveats are well documented below that.
In our apps, we tend to use only simple validators, so most of the caveats don't apply. If we do expand our validators, we could either turn off the option for that schema, or adapt our validators and update queries as per the docs.
That's a good idea. Right now the way to do it would be with a global plugin:
mongoose.plugin(schema => {
schema.pre('findOneAndUpdate', setRunValidators);
schema.pre('updateMany', setRunValidators);
schema.pre('updateOne', setRunValidators);
schema.pre('update', setRunValidators);
});
function setRunValidators() {
this.setOptions({ runValidators: true });
}
Would be neat to have this as a one-liner though.
Some other nice global one-liners might be:
required: true
by default.strict: 'throw'
by default.I have been using those policies in our projects (implemented in our common model builder function) because it helps to detect typos and other developer mistakes sooner. We override the defaults when we need to.
So if you are thinking of introducing some global settings in future, let's try to find something that works neatly for all of those!
Anyway the example above is good enough for me, for now, thanks.
The required: true
one I'm not sure is a good idea. I like the strict: 'throw'
idea though, opened up #6658 to track.
The code below works, and throws an error as expected.
const mongoose = require('mongoose');
const { Schema } = mongoose;
mongoose.plugin(schema => {
schema.pre('findOneAndUpdate', setRunValidators);
schema.pre('updateMany', setRunValidators);
schema.pre('updateOne', setRunValidators);
schema.pre('update', setRunValidators);
});
function setRunValidators () {
this.setOptions({ runValidators: true });
}
mongoose.connect('mongodb://localhost:27017/test', { family: 4, useNewUrlParser: true });
const userSchema = new Schema({
name: { type: String, required: true },
age: { type: Number, min: 13, max: 90 }
});
const User = mongoose.model('User', userSchema);
const hafez = new User({ name: 'Hafez', age: 24 });
async function run () {
await User.remove();
await hafez.save();
await User.updateOne({}, { name: null });
}
run().catch(console.error);
However, running this doesn't work throw an error. I can't seem to find a reference to mongoose.set('runValidators', true);
anywhere in the docs.
const mongoose = require('mongoose');
const { Schema } = mongoose;
mongoose.set('runValidators', true);
mongoose.connect('mongodb://localhost:27017/test', { family: 4, useNewUrlParser: true });
const userSchema = new Schema({
name: { type: String, required: true },
age: { type: Number, min: 13, max: 90 }
});
const User = mongoose.model('User', userSchema);
const hafez = new User({ name: 'Hafez', age: 24 });
async function run () {
await User.remove();
await hafez.save();
await User.updateOne({}, { name: null });
}
run().catch(console.error);
Also would be great to have a global option to setDefaultsOnInsert
.
Thanks for reporting, will investigate ASAP
who can tell me where are the caveats of updating validators? I can't find it.
@tcstory update validators docs are here
@lineus thx
That's a good idea. Right now the way to do it would be with a global plugin:
mongoose.plugin(schema => {
schema.pre('findOneAndUpdate', setRunValidators);
schema.pre('updateMany', setRunValidators);
schema.pre('updateOne', setRunValidators);
schema.pre('update', setRunValidators);
});function setRunValidators() {
this.setOptions({ runValidators: true });
}
Would be neat to have this as a one-liner though.
@vkarpov15
If I set it like this锛孒ow can I cancel runValidators
in once special update?
Tool.findOneAndUpdate({ _id }, { $set: body }, { runValidators: false })
is not work,
The schema.pre
is after Model findOneAndUpdate
~ Will override my customization options
@lqzhgood check https://mongoosejs.com/docs/api.html#query_Query-getOptions
function setRunValidators() {
if ('runValidators' in this.getOptions()) {
return;
}
this.setOptions({ runValidators: true });
}
@vkarpov15 i get "this.setOptions is not a function" error.
it works on local machine btw. but not in production. (and app is running as a docker container)
@yeknava Do you happen to be using an arrow function instead of the code snippet above? Maybe share some code?
sure @AbdelrahmanHafez , here is my code:
function setRunValidators() {
this.setOptions({ runValidators: true, new: true });
}
mongoose.plugin(schema => {
schema.pre('findOneAndUpdate', setRunValidators);
schema.pre('updateMany', setRunValidators);
schema.pre('updateOne', setRunValidators);
schema.pre('update', setRunValidators);
});
Most helpful comment
That's a good idea. Right now the way to do it would be with a global plugin:
Would be neat to have this as a one-liner though.