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.
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 (count > 0) return false;
return true;
}
catch (error) {
return false;
}
}, "Email already exists");