mongoose: beautiful mongodb native errors (unique - code 11000)

I really miss a mechanism that would create validator-like unique index error message. Setting the index of an attribute to unique: true will tell mongodb to return ugly error message like this:

{ [MongoError: insertDocument :: caused by :: 11000 E11000 duplicate key error index: mydb-api.users.$email_1  dup key: { : "my@duplicate.com" }]
  name: 'MongoError',
  code: 11000,
  err: 'insertDocument :: caused by :: 11000 E11000 duplicate key error index: mydb-api.users.$email_1  dup key: { : "my@duplicate.com" }' }

This message should be treated as validator error message thus we could easily display error messages on a REST service.

// koa example
index: function*() {
    try {
      var email = new User(body);
      this.body = yield email.save();
    } catch(e) {
      this.body = e; // nice json errors to display
    }
}

About this issue

  • Original URL
  • State: closed
  • Created 10 years ago
  • Comments: 34 (7 by maintainers)

Commits related to this issue

Most upvoted comments

It does indeed, you just need to set the message as the value of unique.

var userSchema = mongoose.Schema({
    name: {
        type: String,
        unique: 'Custom error message'
    }
});

userSchema.plugin(require('mongoose-beautiful-unique-validation'));

mongoose-unique-validator is a plugin which adds pre-save validation for unique fields within a Mongoose schema. https://github.com/blakehaswell/mongoose-unique-validator

@vkarpov15 as of now I have a wrapper over mongoose, adding this.

Mongoose-unique-validator is doing it wrong. Pre-save validation is not a real solution here, because only unique index guarantees uniqueness.

user A: run pre-save, is the value unique? yes it is. user B: run pre-save, is the value unique? yes it is. user B: insert value user A: insert value (BUG!)

I strongly recommend everyone to use the well-documented package by @matteodelabre at https://github.com/matteodelabre/mongoose-beautiful-unique-validation per my PR here https://github.com/matteodelabre/mongoose-beautiful-unique-validation/pull/40. It is well-tested too and also supports a custom message formatted which builds on top of Mongoose standard error messages, e.g. mongoose.Error.messages.general.unique has a set default value of "Path `{PATH}` ({VALUE}) is not unique." if not already defined.

Furthermore, you can also use my new package mongoose-validation-error-transform at https://github.com/niftylettuce/mongoose-validation-error-transform, which will automatically transform the validation error message to a humanized and readable format.

Here’s how to get started with both of these awesome packages:

npm install --save mongoose-beautiful-unique-validation mongoose-validation-error-transform
const mongooseBeautifulUniqueValidation = require('mongoose-beautiful-unique-validation');
const mongooseValidationErrorTransform = require('mongoose-validation-error-transform');

mongoose.plugin(mongooseBeautifulUniqueValidation);
mongoose.plugin(mongooseValidationErrorTransform);

For example, it will take a message of "full_name" is required and rewrite it to "Full name is required" automatically. It is also excellent for error handling, as it gives you a joined validation error message by comma (e.g. multiple props have validation errors in your schema).

If you wish to customize how the messages are joined, you can provide your own transformation (e.g. you may want to return an err.message that is a <ul> HTML tag of all the errors instead of a plain String joined by a comma. To do so simply pass an options object and override the default transform function.

mongoose.plugin(mongooseValidationErrorTransform, {
  // change this however you like, this is the default:
  transform: function(messages) {
    return messages.join(', '); 
  }
});

To output a <ul> list of error messages, of course you’d only want a <ul> if there’s more than one:

mongoose.plugin(mongooseValidationErrorTransform, {
  // output a <ul> with bootstrap alpha 4 css classes
  transform: function(messages) {
    if (messages.length === 1) return messages[0];
    return `<ul class="text-xs-left mb-0"><li>${messages.join('</li><li>')}</li></ul>`;
  }
});

Complete default options for mongooseValidationErrorTransform are:

{
  capitalize: true,
  humanize: true,
  transform: function(messages) {
    return messages.join(', ');
  }
}

I created one that I expect to grow to handle most common MongoErrors, this one is using the 4.5 middlewares.

https://github.com/jhenriquez/mongoose-mongodb-errors