之前,我们是这样往数据库内添加文档的:
const courseSchema = mongoose.Schema({
name: String,
auther: String,
tags: [ String ],
date: { type: Date, default: Date.now },
isPublished: Boolean
});
const Course = mongoose.model('Course',courseSchema); //返回值是一个类,故用大写命名
async function createCourse(){
const course = new Course({
name:'数据结构',
auther:'刘晓霞',
tags: ['算法','递归','复杂度'],
isPublished:true
});
const result = await course.save(); //save()是一个异步方法,它返回一个Promise对象
console.log(result);
}
我们没有做验证,这将导致即使文档的所有属性字段为空也能成功存储在数据库内。
1.required验证器(mongoose的内建验证器)
为解决这个问题,我们将对数据进行验证(validation)。
在创建schema时可以使用一个对象替代一个类型:name: { type : String, required : true}
然后在创建课程时加入异常处理即可:
async function createCourse(){
const course = new Course({
//name:'数据结构',
auther:'刘晓霞',
tags: ['算法','递归','复杂度'],
isPublished:true
});
try{
//await course.validate();
const result = await course.save(); //save()是一个异步方法,它返回一个Promise对象
console.log(result);
}catch(err){
console.log(err.message);
}
}
但这里似乎有一个问题:那就是即使做了验证,数据还是会被成功存入数据库。
name: { type : String, reqiured : true}
这里的required既可以是一个布尔值,也可以是一个返回布尔值的函数,下面这个例子就实现了当isPublished属性为true是才验证name属性必须存在:
name: { type : String, required : function(){return this.isPublished}}
2.自定义验证器
tags: {
type:Array,
validate:{
validator:function(v){
return v.length > 0;
},
message:"每个课程至少要有1个标签"
}
}
3.异步验证器
tags: {
type:Array,
validate:{
isAsync:true,
validator:function(v ,callback){
setTimeout(() => {
//用setTimeout来模拟异步操作,这里可能是读取数据库或者访问远程服务器
const result = v && v.length>0;
callback(result);
},4000);
},
message:"每个课程至少要有1个标签"
}
}
4.处理多个异常
//创建课程的异步方法
async function createCourse(){
const course = new Course({
//name:'数据结构',
auther:'刘晓霞',
tags: null,
isPublished:true
});
try{
//await course.validate();
const result = await course.save(); //save()是一个异步方法,它返回一个Promise对象
console.log(result);
}catch(err){
//console.log(err.message);
//err.errors.tags
//err.errors.name
for(field in err.errors){
console.log(err.errors[field]);
}
}
}
运行结果中出现两个错误:
MongooseError [ValidatorError]: Path `name` is required.
at new ValidatorError (C:\Users\Zijeak\Desktop\mongo-demo\node_modules\mongoose\lib\error\validator.js:29:11)
at validate (C:\Users\Zijeak\Desktop\mongo-demo\node_modules\mongoose\lib\schematype.js:1170:13)
at C:\Users\Zijeak\Desktop\mongo-demo\node_modules\mongoose\lib\schematype.js:1153:7
at Array.forEach (<anonymous>)
at SchemaString.SchemaType.doValidate (C:\Users\Zijeak\Desktop\mongo-demo\node_modules\mongoose\lib\schematype.js:1098:14)
at C:\Users\Zijeak\Desktop\mongo-demo\node_modules\mongoose\lib\document.js:2372:18
at processTicksAndRejections (internal/process/task_queues.js:79:11) {
message: 'Path `name` is required.',
name: 'ValidatorError',
properties: {
validator: [Function],
message: 'Path `name` is required.',
type: 'required',
path: 'name',
value: undefined
},
kind: 'required',
path: 'name',
value: undefined,
reason: undefined,
[Symbol(mongoose:validatorError)]: true
}
MongooseError [ValidatorError]: 每个课程至少要有1个标签
at new ValidatorError (C:\Users\Zijeak\Desktop\mongo-demo\node_modules\mongoose\lib\error\validator.js:29:11)
at validate (C:\Users\Zijeak\Desktop\mongo-demo\node_modules\mongoose\lib\schematype.js:1170:13)
at C:\Users\Zijeak\Desktop\mongo-demo\node_modules\mongoose\lib\schematype.js:1193:5
at Timeout._onTimeout (C:\Users\Zijeak\Desktop\mongo-demo\index.js:20:21)
at listOnTimeout (internal/timers.js:549:17)
at processTimers (internal/timers.js:492:7) {
message: '每个课程至少要有1个标签',
name: 'ValidatorError',
properties: {
isAsync: true,
validator: [Function: validator],
message: '每个课程至少要有1个标签',
type: 'user defined',
path: 'tags',
value: null
},
kind: 'user defined',
path: 'tags',
value: null,
reason: undefined,
[Symbol(mongoose:validatorError)]: true
}
5.schema的选项