Andrew Korin
Andrew Korin

Reputation: 304

Why validation runs on field update in mongoose?

I know that there shouldn't be any validation on field update but it runs anyway when I try to migrate a database.

Part of the migration:

const arr = await User.find({ ban: { $exists: true } });
arr.forEach(async item => {
  // this works
  // await User.updateOne({ _id: item._id }, { ban: false });
  // this doesn't
  item.ban = false;
  await item.save();
});

Part of the schema:

email: {
  type: String,
  validate: {
    validator: email => User.doesntExist({ email }),
    message: ({ value }) => `Email ${value} has already been taken`
  }
}

"ValidationError: User validation failed: email: Email [email protected] has already been taken"

Upvotes: 0

Views: 453

Answers (3)

Jake Noh
Jake Noh

Reputation: 216

There is an option for disabling validator to be fired in mongoose save(), which is validateBeforeSave. (since mongoose version 4.4.2)

So try to use save({ validateBeforeSave: false }) if you want to keep using save() instead of update().

Upvotes: 1

lifeisfoo
lifeisfoo

Reputation: 16294

You're doing it right, because as reported in mongoose documentation:

The save() function is generally the right way to update a document with Mongoose. With save(), you get full validation and middleware.

But, when you call the .save() function, all validators are called, including your user email validator:

validator: email => User.doesntExist({ email })

And in your case this is a problem, because the user being validated is already saved in the db... So, to avoid this you need to use the .update() function in order to update your users.

Upvotes: 1

musti
musti

Reputation: 31

https://mongoosejs.com/docs/validation.html#validation

Validation is middleware. Mongoose registers validation as a pre('save') hook on every schema by default.

updateOne doesn't triggers save hook.

Upvotes: 0

Related Questions