Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Configuration to make runValidators default to true? #6578

Closed
joeytwiddle opened this issue Jun 11, 2018 · 14 comments
Closed

Configuration to make runValidators default to true? #6578

joeytwiddle opened this issue Jun 11, 2018 · 14 comments
Milestone

Comments

@joeytwiddle
Copy link
Contributor

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.

@vkarpov15
Copy link
Collaborator

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 vkarpov15 added this to the 5.2 milestone Jun 13, 2018
vkarpov15 added a commit that referenced this issue Jun 29, 2018
@joeytwiddle
Copy link
Contributor Author

Some other nice global one-liners might be:

  • Make all fields required: true by default.
  • Make all schemas 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.

@vkarpov15
Copy link
Collaborator

The required: true one I'm not sure is a good idea. I like the strict: 'throw' idea though, opened up #6658 to track.

@AbdelrahmanHafez
Copy link
Collaborator

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);

@AbdelrahmanHafez
Copy link
Collaborator

Also would be great to have a global option to setDefaultsOnInsert.

@vkarpov15 vkarpov15 reopened this Aug 15, 2018
@vkarpov15 vkarpov15 modified the milestones: 5.2, 5.2.9 Aug 15, 2018
@vkarpov15 vkarpov15 removed the fixed? label Aug 15, 2018
@vkarpov15
Copy link
Collaborator

Thanks for reporting, will investigate ASAP

vkarpov15 added a commit that referenced this issue Aug 15, 2018
@tcstory
Copy link

tcstory commented Nov 1, 2018

who can tell me where are the caveats of updating validators? I can't find it.

@ghost
Copy link

ghost commented Nov 1, 2018

@tcstory
Copy link

tcstory commented Nov 1, 2018

@lineus thx

@lqzhgood
Copy link

lqzhgood commented Dec 11, 2018

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,How 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

@vkarpov15
Copy link
Collaborator

@lqzhgood check https://mongoosejs.com/docs/api.html#query_Query-getOptions

  function setRunValidators() {
    if ('runValidators' in this.getOptions()) {
      return;
    }
    this.setOptions({ runValidators: true });
  }

@yeknava
Copy link

yeknava commented May 24, 2019

@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)

@AbdelrahmanHafez
Copy link
Collaborator

@yeknava Do you happen to be using an arrow function instead of the code snippet above? Maybe share some code?

@yeknava
Copy link

yeknava commented May 24, 2019

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);
});

@Automattic Automattic locked as resolved and limited conversation to collaborators May 26, 2019
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

No branches or pull requests

6 participants