Home > Enterprise >  Mongoose: MongoError won't prevent pre hooks to run?
Mongoose: MongoError won't prevent pre hooks to run?

Time:01-17

I'm using Mocha to make some tests in my API and I noticed that when I have a field with unique: true and I make the tests on a duplicate field, all of my pre('save') still are called. Am I doing something wrong?

user.js

const UserSchema = new Schema({
  email: {
    type: String,
    unique: true
  }
});

UserSchema.pre('save', function test(next) {
  console.log(123);
});

test.js

var user1 = await User.findOne({ email: "[email protected]" });
var user2 = new User({ email: "[email protected]" });
await user2.save()

console:

123
MongoError: E11000 duplicate key error collection (...)

Here there is an image of my test. In the "creates a new document when valid" I create two new users. In the "email is unique ..." test, I try to create another with the same email as I created before. The "1234567" are console.log I put inside my pre hook.

CodePudding user response:

After a lot of research I discovered how things work with unique and pre hooks.

This is the best way to fix this kind of problem.

Edit: some details for this answer as Tyler appointed that it could become invalid.

In my case, my pre saves have crucial logic with relationships. So when I was trying to save an invalid document, all the relationships of it were being associated with a wrong document.

Since async pre hooks are called all together, I had to garantee that my unique validation was called before everything. Using .path('field').validate was the best way I found so far to do it, since it is called even before .pre('validate'). Here is my code:

UserSchema.path('email').validate(async function validateDuplicatedEmail(value) {
    if (!this.isNew && !this.isModified('email')) return true;

    try {
        const User = mongoose.model("User");

        const count = await User.countDocuments({ email: value });
        if ((this.isNew && count > 0) || (this.isModified('email') && count > 0)) return false;

        return true;
    }
    catch (error) {
        return false;
    }
}, "Email already exists");

  •  Tags:  
  • Related