美文网首页
Mongoose 笔记

Mongoose 笔记

作者: Cause_XL | 来源:发表于2017-04-10 16:04 被阅读0次

    Mongoose 笔记

    官网指南

    参考链接

    名词解释

    Schema: 一种以文件形式存储的数据库模型骨架,不具备数据库的操作能力

    Model: 由Schema发布生成的模型,具有抽象属性和行为的数据库操作对

    Entity: 由Model创建的实体,他的操作也会影响数据库

    Schema、Model、Entity的关系请牢记,Schema生成Model,Model创造Entity,Model和Entity都可对数据库操作造成影响,但Model比Entity更具操作性。

    链接数据库&创建模型

    
    var mongoose = require('mongoose');    //引用mongoose模块
    
    var db = mongoose.createConnection('localhost','test'); //创建一个数据库连接
    
    db.on('error',console.error.bind(console,'连接错误:'));
    
    db.once('open',function(){
    
    //一次打开记录
    
    });
    
    //定义一个Schema
    
    var PersonSchema = new mongoose.Schema({
    
    name:String  //定义一个属性name,类型为String
    
    });
    
    //将该Schema发布为Model
    
    var PersonModel = db.model('Person',PersonSchema);
    
    //如果该Model已经发布,则可以直接通过名字索引到,如下:
    
    //var PersonModel = db.model('Person');
    
    //如果没有发布,上一段代码将会异常
    
    //用Model创建Entity
    
    var personEntity = new PersonModel({name:'Krouky'});
    
    //打印这个实体的名字看看
    
    console.log(personEntity.name); //Krouky
    
    

    我们甚至可以为此Schema创建方法

    
    //为Schema模型追加speak方法
    
    PersonSchema.methods.speak = function(){
    
    console.log('我的名字叫'+this.name);
    
    }
    
    var PersonModel = db.model('Person',PersonSchema);
    
    var personEntity = new PersonModel({name:'Krouky'});
    
    personEntity.speak();//我的名字叫Krouky
    
    //Entity是具有具体的数据库操作CRUD的
    
    personEntity.save();  //执行完成后,数据库就有该数据了
    
    //如果要执行查询,需要依赖Model,当然Entity也是可以做到的
    
    PersonModel.find(function(err,persons){
    
    //查询到的所有person
    
    });
    
    

    查询

    通常有2种查询方式,一种是直接查询,一种是链式查询(2种查询都是自己命名的)

    直接查询

    在查询时带有回调函数的,称之为直接查询,查询的条件往往通过API来设定,例如:

    
    PersonModel.findOne({'name.last':'dragon'},'some select',function(err,person){
    
    //如果err==null,则person就能取到数据
    
    });
    
    

    链式查询

    在查询时候,不带回调,而查询条件通过API函数来制定,例如:

    
    var query = PersonModel.findOne({'name.last':'dragon'});
    
    query.select('some select');
    
    query.exec(function(err,pserson){
    
    //如果err==null,则person就能取到数据
    
    });
    
    

    因为query的操作始终返回自身,我们可以采用更形象的链式写法

    
    Person
    
    .find({ occupation: /host/ })
    
    .where('name.last').equals('Ghost')
    
    .where('age').gt(17).lt(66)
    
    .where('likes').in(['vaporizing', 'talking'])
    
    .limit(10)
    
    .sort('-occupation')
    
    .select('name occupation')
    
    .exec(callback);
    
    

    更新

    有许多方式来更新文件,以下是常用的传统方式:

    
    PersonModel.findById(id,function(err,person){
    
    person.name = 'MDragon';
    
    person.save(function(err){});
    
    });
    
    

    这里,利用Model模型查询到了person对象,该对象属于Entity,可以有save操作,如果使用Model`操作,需注意:

    
    PersonModel.findById(id,function(err,person){
    
    person.name = 'MDragon';
    
    var _id = person._id; //需要取出主键_id
    
    delete person._id;    //再将其删除
    
    PersonModel.update({_id:_id},person,function(err){});
    
    //此时才能用Model操作,否则报错
    
    });
    
    

    update第一个参数是查询条件,第二个参数是更新的对象,但不能更新主键,这就是为什么要删除主键的原因。

    当然这样的更新很麻烦,可以使用$set属性来配置,这样也不用先查询,如果更新的数据比较少,可用性还是很好的:

    
    PersonModel.update({_id:_id},{$set:{name:'MDragon'}},function(err){});
    
    

    需要注意,Document的CRUD操作都是异步执行,callback第一个参数必须是err,而第二个参数各个方法不一样,update的callback第二个参数是更新的数量,如果要返回更新后的对象,则要使用如下方法

    
    Person.findByIdAndUpdate(_id,{$set:{name:'MDragon'}},function(err,person){
    
    console.log(person.name); //MDragon
    
    });
    
    

    类似的方法还有findByIdAndRemove,如同名字,只能根据id查询并作update/remove操作,操作的数据仅一条

    新增

    如果是Entity,使用save方法,如果是Model,使用create方法

    
    //使用Entity来增加一条数据
    
    var krouky = new PersonModel({name:'krouky'});
    
    krouky.save(callback);
    
    //使用Model来增加一条数据
    
    var MDragon = {name:'MDragon'};
    
    PersonModel.create(MDragon,callback);
    
    

    两种新增方法区别在于,如果使用Model新增时,传入的对象只能是纯净的JSON对象,不能是由Model创建的实体,原因是:由Model创建的实体krouky虽然打印是只有{name:'krouky'},但是krouky属于Entity,包含有Schema属性和Model数据库行为模型。如果是使用Model创建的对象,传入时一定会将隐藏属性也存入数据库,虽然3.x追加了默认严格属性,但也不必要增加操作的报错

    删除

    和新增一样,删除也有2种方式,但Entity和Model都使用remove方法

    Sub Docs

    如同SQL数据库中2张表有主外关系,Mongoose将2个Document的嵌套叫做Sub-Docs(子文档)

    简单的说就是一个Document嵌套另外一个Document或者Documents:

    
    var ChildSchema1 = new Schema({name:String});
    
    var ChildSchema2 = new Schema({name:String});
    
    var ParentSchema = new Schema({
    
    children1:ChildSchema1,  //嵌套Document
    
    children2:[ChildSchema2]  //嵌套Documents
    
    });
    
    

    Sub-Docs享受和Documents一样的操作,但是Sub-Docs的操作都由父类去执行

    
    var ParentModel = db.model('Parent',parentSchema);
    
    var parent = new ParentModel({
    
    children2:[{name:'c1'},{name:'c2'}]
    
    });
    
    parent.children2[0].name = 'd';
    
    parent.save(callback);
    
    

    parent在执行保存时,由于包含children2,他是一个数据库模型对象,因此会先保存chilren2[0]和chilren2[1]。

    如果子文档在更新时出现错误,将直接报在父类文档中,可以这样处理:

    
    ChildrenSchema.pre('save',function(next){
    
    if('x' === this.name) return next(new Error('#err:not-x'));
    
    next();
    
    });
    
    var parent = new ParentModel({children1:{name:'not-x'}});
    
    parent.save(function(err){
    
    console.log(err.message); //#err:not-x
    
    });
    
    

    验证器

    required 非空验证

    min/max 范围验证(边值验证)

    enum/match 枚举验证/匹配验证

    validate 自定义验证规则

    以下是综合案例:

    
    var PersonSchema = new Schema({
    
    name:{
    
    type:'String',
    
    required:true //姓名非空
    
    },
    
    age:{
    
    type:'Nunmer',
    
    min:18,      //年龄最小18
    
    max:120    //年龄最大120
    
    },
    
    city:{
    
    type:'String',
    
    enum:['北京','上海']  //只能是北京、上海
    
    },
    
    other:{
    
    type:'String',
    
    validate:[validator,err]  //validator是一个验证函数,err是验证失败的错误信息
    
    }
    
    });
    
    

    验证失败

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

    err.errors //错误集合(对象)

    err.errors.color //错误属性(Schema的color属性)

    err.errors.color.message //错误属性信息

    err.errors.path //错误属性路径

    err.errors.type //错误类型

    err.name //错误名称

    err.message //错误消息

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

    Middleware中间件

    什么是中间件

    中间件是一种控制函数,类似插件,能控制流程中的init、validate、save、remove`方法

    中间件的分类

    中间件分为两类

    Serial串行

    串行使用pre方法,执行下一个方法使用next调用

    
    var schema = new Schema(...);
    
    schema.pre('save',function(next){
    
    //做点什么
    
    next();
    
    });
    
    

    Parallel并行

    并行提供更细粒度的操作

    
    var schema = new Schema(...);
    
    schema.pre('save',function(next,done){
    
    //下一个要执行的中间件并行执行
    
    next();
    
    doAsync(done);
    
    });
    
    

    中间件特点

    一旦定义了中间件,就会在全部中间件执行完后执行其他操作,使用中间件可以雾化模型,避免异步操作的层层迭代嵌套

    使用范畴

    复杂的验证

    删除有主外关联的doc

    异步默认

    某个特定动作触发异步任务,例如触发自定义事件和通知

    例如,可以用来做自定义错误处理

    
    schema.pre('save',function(next){
    
    var err = new Eerror('some err');
    
    next(err);
    
    });
    
    entity.save(function(err){
    
    console.log(err.message); //some err
    
    });
    
    

    相关文章

      网友评论

          本文标题:Mongoose 笔记

          本文链接:https://www.haomeiwen.com/subject/njnsattx.html