3.4 Mongoose Schema的类型校验

为什么需要文档验证呢?以一个例子作为说明,schema进行如下定义

var schema = new mongoose.Schema({ age:Number, name: String,x:Number,y:Number});

如果不进行文档验证,保存文档时,就可以不按照Schema设置的字段进行设置,分为以下几种情况

缺少字段的文档可以保存成功

var temp = mongoose.model('temp', schema);
new temp({age:10}).save(function(err,doc){
    //{ __v: 0, age: 10, _id: 597304442b70086a1ce3cf05 }
    console.log(doc);
});

包含未设置的字段的文档也可以保存成功,

未设置的字段不被保存

new temp({age:100,abc:"abc"}).save(function(err,doc){
    //{ __v: 0, age: 100, _id: 5973046a2bb57565b474f48b }
    console.log(doc);
});

包含字段类型与设置不同的字段的文档也可以保存成功,

不同字段类型的字段被保存为设置的字段类型

new temp({age:true,name:10}).save(function(err,doc){
    //{ __v: 0, age: 1, name: '10', _id: 597304f7a926033060255366 }
    console.log(doc);
});

而通过文档验证,就可以避免以下几种情况发生

规则

数据的存储是需要验证的,不是什么数据都能往数据库里丢或者显示到客户端的,数据的验证需要记住以下规则:

  • 验证始终定义在SchemaType

  • 验证是一个内部中间件

  • 验证是在一个Document被保存时默认启用的,除非你关闭验证

  • 验证是异步递归的,如果你的SubDoc验证失败,Document也将无法保存

  • 验证并不关心错误类型,而通过ValidationError这个对象可以访问

格式

{name: {type:String, validator:value}}

常用验证包括以下几种

  • required: 数据必须填写

  • default: 默认值

  • validate: 自定义匹配

  • min: 最小值(只适用于数字)

  • max: 最大值(只适用于数字)

  • match: 正则匹配(只适用于字符串)

  • enum: 枚举匹配(只适用于字符串)

required

将age设置为必填字段,如果没有age字段,文档将不被保存,且出现错误提示

var schema = new mongoose.Schema({ age:{type:Number,required:true}, name: String,x:Number,y:Number});  
var temp = mongoose.model('temp', schema);
new temp({name:"abc"}).save(function(err,doc){
    //Path `age` is required.
    console.log(err.errors['age'].message);
});

default

设置age字段的默认值为18,如果不设置age字段,则会取默认值

var schema = new mongoose.Schema({ age:{type:Number,default:18}, name:String,x:Number,y:Number});  
var temp = mongoose.model('temp', schema);
new temp({name:'a'}).save(function(err,doc){
    //{ __v: 0, name: 'a', _id: 59730d2e7a751d81582210c1, age: 18 }
    console.log(doc);
});

min | max

将age的取值范围设置为[0,10]。如果age取值为20,文档将不被保存,且出现错误提示

var schema = new mongoose.Schema({ age:{type:Number,min:0,max:10}, name: String,x:Number,y:Number});  
var temp = mongoose.model('temp', schema);
new temp({age:20}).save(function(err,doc){
    //Path `age` (20) is more than maximum allowed value (10).
    console.log(err.errors['age'].message);
});

match

将name的match设置为必须存在'a'字符。如果name不存在'a',文档将不被保存,且出现错误提示

var schema = new mongoose.Schema({ age:Number, name:{type:String,match:/a/},x:Number,y:Number});  
var temp = mongoose.model('temp', schema);
new temp({name:'bbb'}).save(function(err,doc){
    //Path `name` is invalid (bbb).
    console.log(err.errors['name'].message);
});

enum

将name的枚举取值设置为['a','b','c'],如果name不在枚举范围内取值,文档将不被保存,且出现错误提示

var schema = new mongoose.Schema({ age:Number, name:{type:String,enum:['a','b','c']},x:Number,y:Number});  
var temp = mongoose.model('temp', schema);
new temp({name:'bbb'}).save(function(err,doc){
    //`bbb` is not a valid enum value for path `name`.
    console.log(err.errors['name'].message);

});

validate

validate实际上是一个函数,函数的参数代表当前字段,返回true表示通过验证,返回false表示未通过验证。利用validate可以自定义任何条件。比如,定义名字name的长度必须在4个字符以上

var validateLength = function(arg,err){
    //validate:[validator,err]  //validator是一个验证函数,err是验证失败的错误信息
    if(arg.length > 4){
        return true;
    }
    err.message='长度不对'
    return false;
};
var schema = new mongoose.Schema({ name:{type:String,validate:validateLength}, age:Number,x:Number,y:Number});  
var temp = mongoose.model('temp', schema);
new temp({name:'abc'}).save(function(err,doc){
    //Validator failed for path `name` with value `abc`
    console.log(err.errors['name'].message);
});

验证失败

如果验证失败,则会返回err信息,err是一个对象该对象属性如下

    err.errors                //错误集合(对象)
    err.errors.color          //错误属性(Schema的color属性)
    err.errors.color.message  //错误属性信息
    err.errors.path             //错误属性路径
    err.errors.type             //错误类型
    err.name                //错误名称
    err.message                 //错误消息

一旦验证失败,ModelEntity都将具有和err一样的errors属性

可以从回调函数中接收err 信息

Last updated

Was this helpful?