新知识

您可以为架构中的各个验证程序配置错误消息。有两种等效的方法来设置验证程序错误消息:

  • 数组语法:min: [6, 'Must be at least 6, got {VALUE}']
  • 对象语法:enum: { values: ['Coffee', 'Tea'], message: '{VALUE} is not supported' }

猫鼬还支持错误消息的基本模板。猫鼬将替换为正在验证的值。{VALUE}

const breakfastSchema = new Schema({
  eggs: {
    type: Number,
    min: [6, 'Must be at least 6, got {VALUE}'],
    max: 12
  },
  drink: {
    type: String,
    enum: {
      values: ['Coffee', 'Tea'],
      message: '{VALUE} is not supported'
    }
  }
});
const Breakfast = db.model('Breakfast', breakfastSchema);

const badBreakfast = new Breakfast({
  eggs: 2,
  drink: 'Milk'
});
let error = badBreakfast.validateSync();
assert.equal(error.errors['eggs'].message,
  'Must be at least 6, got 2');
assert.equal(error.errors['drink'].message, 'Milk is not supported');

一选项不是验证程序

初学者的一个常见问题是,架构的选项不是验证器。它是构建MongoDB唯一索引的便捷助手。有关详细信息,请参阅常见问题解答unique

const uniqueUsernameSchema = new Schema({
  username: {
    type: String,
    unique: true
  }
});
const U1 = db.model('U1', uniqueUsernameSchema);
const U2 = db.model('U2', uniqueUsernameSchema);

const dup = [{ username: 'Val' }, { username: 'Val' }];
U1.create(dup, err => {
  // Race condition! This may save successfully, depending on whether
  // MongoDB built the index before writing the 2 docs.
});

// You need to wait for Mongoose to finish building the `unique`
// index before writing. You only need to build indexes once for
// a given collection, so you normally don't need to do this
// in production. But, if you drop the database between tests,
// you will need to use `init()` to wait for the index build to finish.
U2.init().
  then(() => U2.create(dup)).
  catch(error => {
    // Will error, but will *not* be a mongoose validation error, it will be
    // a duplicate key error.
    // See: https://masteringjs.io/tutorials/mongoose/e11000-duplicate-key
    assert.ok(error);
    assert.ok(!error.errors);
    assert.ok(error.message.indexOf('duplicate key error') !== -1);
  });

自定义验证程序

如果内置验证程序不够,您可以定义自定义验证程序以满足您的需求。

通过传递验证函数来声明自定义验证。您可以在SchemaType#validate() API 文档中找到有关如何执行此操作的详细说明。

const userSchema = new Schema({
  phone: {
    type: String,
    validate: {
      validator: function(v) {
        return /\d{3}-\d{3}-\d{4}/.test(v);
      },
      message: props => `${props.value} is not a valid phone number!`
    },
    required: [true, 'User phone number required']
  }
});

const User = db.model('user', userSchema);
const user = new User();
let error;

user.phone = '555.0123';
error = user.validateSync();
assert.equal(error.errors['phone'].message,
  '555.0123 is not a valid phone number!');

user.phone = '';
error = user.validateSync();
assert.equal(error.errors['phone'].message,
  'User phone number required');

user.phone = '201-555-0123';
// Validation succeeds! Phone number is defined
// and fits `DDD-DDD-DDDD`
error = user.validateSync();
assert.equal(error, null);

异步自定义验证程序

自定义验证程序也可以是异步的。如果你的验证器函数返回一个承诺(就像一个函数),猫鼬会等待这个承诺解决。如果返回的承诺被拒绝,或者用值满足,猫鼬会认为这是一个验证错误。asyncfalse

const userSchema = new Schema({
  name: {
    type: String,
    // You can also make a validator async by returning a promise.
    validate: () => Promise.reject(new Error('Oops!'))
  },
  email: {
    type: String,
    // There are two ways for an promise-based async validator to fail:
    // 1) If the promise rejects, Mongoose assumes the validator failed with the given error.
    // 2) If the promise resolves to `false`, Mongoose assumes the validator failed and creates an error with the given `message`.
    validate: {
      validator: () => Promise.resolve(false),
      message: 'Email validation failed'
    }
  }
});

const User = db.model('User', userSchema);
const user = new User();

user.email = 'test@test.co';
user.name = 'test';
user.validate().catch(error => {
  assert.ok(error);
  assert.equal(error.errors['name'].message, 'Oops!');
  assert.equal(error.errors['email'].message, 'Email validation failed');
});

验证错误

验证失败后返回的错误包含值为对象的对象。每个验证器错误都有 、 、 和属性。验证者错误也可能具有属性。如果在验证程序中抛出错误,则此属性将包含引发的错误。errorsValidatorErrorkindpathvaluemessagereason

const toySchema = new Schema({
  color: String,
  name: String
});

const validator = function(value) {
  return /red|white|gold/i.test(value);
};
toySchema.path('color').validate(validator,
  'Color `{VALUE}` not valid', 'Invalid color');
toySchema.path('name').validate(function(v) {
  if (v !== 'Turbo Man') {
    throw new Error('Need to get a Turbo Man for Christmas');
  }
  return true;
}, 'Name `{VALUE}` is not valid');

const Toy = db.model('Toy', toySchema);

const toy = new Toy({ color: 'Green', name: 'Power Ranger' });

toy.save(function(err) {
  // `err` is a ValidationError object
  // `err.errors.color` is a ValidatorError object
  assert.equal(err.errors.color.message, 'Color `Green` not valid');
  assert.equal(err.errors.color.kind, 'Invalid color');
  assert.equal(err.errors.color.path, 'color');
  assert.equal(err.errors.color.value, 'Green');

  // This is new in mongoose 5. If your validator throws an exception,
  // mongoose will use that message. If your validator returns `false`,
  // mongoose will use the 'Name `Power Ranger` is not valid' message.
  assert.equal(err.errors.name.message,
    'Need to get a Turbo Man for Christmas');
  assert.equal(err.errors.name.value, 'Power Ranger');
  // If your validator threw an error, the `reason` property will contain
  // the original error thrown, including the original stack trace.
  assert.equal(err.errors.name.reason.message,
    'Need to get a Turbo Man for Christmas');

  assert.equal(err.name, 'ValidationError');
});
上一篇:PHP的错误机制总结


下一篇:haproxy tcp 白名单配置说明