mongoose: unique validation on update

Richard LIU
Nov 2 · 2 min read

Issue

By default the validator logic won’t execute when you update a document using mongoose update APIs (e.g. findOneAndUpdate).

As suggested in this answer, you can use the following code as a workaround:

UserInfo.findOne({ userId: userInfo.userId })
.then((ui) => {
ui.set(userInfo);
return ui.save();
})

This worked perfectly until I introduced mongoose-unique-validator.

mongoose-unique-validator

The mongoose-unique-validator package is necessary because without it, if you violates unique constraint, you will get a vague E11000 error from mongoDB.

{
code: 11000
driver: true
errmsg: "E11000 duplicate key error collection: archiprod.userinfos index: phone_1 dup key: { : "01234567891" }"
index: 0
name: "MongoError"
}

It has at least two issues when you want to tell the user which field violates the unique constraint.

  • it’s not well structured, so you have to extract the info from the errmsg field manually.
  • It only returns on the first violation. So if you have two or more violations at the same time, you can’t show them all to the user.

It’s no longer an issue with mongoose-unique-validator, because you can get the following structured error message:

{
"_message": "UserInfo validation failed",
"errors": {
"email": {
"kind": "unique",
"message": "Error, expected `email` to be unique. Value: `test@gmail.com`",
"name": "ValidatorError",
"path": "email",
"properties": {
"message": "Error, expected `email` to be unique. Value: `test@gmail.com`",
"path": "email",
"type": "unique",
"value": "test@gmail.com"
},
"value": "test@gmail.com"
},
"phone": {
"kind": "unique",
"message": "Error, expected `phone` to be unique. Value: `01234567891`",
"name": "ValidatorError",
"path": "phone",
"properties": {
"message": "Error, expected `phone` to be unique. Value: `01234567891`",
"path": "phone",
"type": "unique",
"value": "01234567891"
},
"value": "01234567891"
}
},
"message": "UserInfo validation failed: email: Error, expected `email` to be unique. Value: `test@gmail.com`, phone: Error, expected `phone` to be unique. Value: `01234567891`",
"name": "ValidationError"
}
Welcome to a place where words matter. On Medium, smart voices and original ideas take center stage - with no ads in sight. Watch
Follow all the topics you care about, and we’ll deliver the best stories for you to your homepage and inbox. Explore
Get unlimited access to the best stories on Medium — and support writers while you’re at it. Just $5/month. Upgrade