您可以为架构中的各个验证程序配置错误消息。有两种等效的方法来设置验证程序错误消息:
- 数组语法:
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);
异步自定义验证程序
自定义验证程序也可以是异步的。如果你的验证器函数返回一个承诺(就像一个函数),猫鼬会等待这个承诺解决。如果返回的承诺被拒绝,或者用值满足,猫鼬会认为这是一个验证错误。async
false
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');
});
验证错误
验证失败后返回的错误包含值为对象的对象。每个验证器错误都有 、 、 和属性。验证者错误也可能具有属性。如果在验证程序中抛出错误,则此属性将包含引发的错误。errors
ValidatorError
kind
path
value
message
reason
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');
});