nodejs操作mongodb数据库(mongoose)

来源:互联网 发布:星空倒影 知乎 编辑:程序博客网 时间:2024/04/29 05:10

准备

在上一篇的基础上,通过npm安装mongoose。

关于mongoose

Mongoose是MongoDB的一个对象模型工具,是基于node-mongodb-native开发的MongoDB nodejs驱动,可以在异步的环境下执行。同时它也是针对MongoDB操作的一个对象模型库,封装了MongoDB对文档的的一些增删改查等常用方法,让NodeJS操作Mongodb数据库变得更加灵活简单。

Schema : 一种以文件形式存储的数据库模型骨架,不具备数据库的操作能力
Model : 由Schema发布生成的模型,具有抽象属性和行为的数据库操作对
Entity : 由Model创建的实体,他的操作也会影响数据库

它们之间的关系是Schema生成Model,Model创造Entity,Model和Entity都可对数据库操作造成影响,但Model比Entity更具操作性。Model对应collection,Entity对应docment。

Mongoose API:http://mongoosejs.com/docs/api.html

CRUD操作

1.增加

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

// mongoose 链接var mongoose = require('mongoose');var db       = mongoose.connect('mongodb://127.0.0.1:27017/chm'); // 链接错误db.connection.on('error', function(error) {    console.log(error);});db.connection.on("open", function () { console.log("——数据库连接成功!——"); });// Schema 结构var vipSchema = new mongoose.Schema({    name : {type : String, default : 'java'},    addr    : {type : String},    addTime  : {type : Date, default: Date.now},    age      : {type : Number}});//中间件//save之前触发vipSchema.pre('save', function(next){    console.log("pre save");    next();});vipSchema.post('save', function (doc) {    //doc是当前插入的文档    console.log(doc);});// modelvar vipModel = db.model('vip', vipSchema);// 增加记录 基于 entity 操作var doc = {name : 'java', age:20, addr:"shanghai"};var vipEntity= new vipModel(doc);vipEntity.save(function(error) {    if(error) {        console.log(error);    } else {        console.log('saved OK!');    }    // 关闭数据库链接    db.disconnect();});//增加记录 基于model操作vipModel.create(doc, function(error){    if(error) {        console.log(error);    } else {        console.log('save ok');    }    // 关闭数据库链接    db.disconnect();});

这里有个问题,当执行完上面的代码后,到数据库中执行db.vip.find();命令你会发现查不到刚添加的那条数据,再执行show collections你会发现多了一个vips集合,数据在这个集合里面。这里Mongoose在模型名至数据库集合名的命名转换上做了文章,下面会介绍。
2.查找

var mongoose = require("mongoose");var db = mongoose.connect('mongodb://localhost:27017/chm'); db.connection.on("error", function (error) { console.log("数据库连接失败:" + error); }); db.connection.on("open", function () { console.log("——数据库连接成功!——"); });var Schema = mongoose.Schema;//模板var vipSchema = new Schema({    name:String,    age:Number,    addr:String,    addTime:Date});// 添加 mongoose 实例方法vipSchema.methods.findByName = function(hello, callback) {    return this.model('vips').find({name: hello}, callback);}// 添加 mongoose 静态方法,静态方法在Model层就能使用vipSchema.statics.findbyage = function(age, callback) {    return this.model('vips').find({age: age}, callback);}//模型var vipModel = mongoose.model('vips', vipSchema);vipModel.find({name:"java"},function(error, result){    if(error) {        console.log(error);    } else {        console.log(result);    }    //关闭数据库链接    db.disconnect(); });//基于实例方法的查询var entity = new vipModel({"name":"java"});entity.findByName("java",function(error, result){    if(error) {        console.log(error);    } else {        console.log(result);    }    //关闭数据库链接    db.disconnect();});//基于静态方法的查询vipModel.findbyage(20, function(error, result){    if(error) {        console.log(error);    } else {        console.log(result);    }    //关闭数据库链接    db.disconnect();;});

另一种查询:查询时不带回调

vipModel      .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);

如果不带callback,则返回query,query没有执行的预编译查询语句,该query对象执行的方法都将返回自己,只有在执行exec方法时才执行查询,而且必须有回调。

3.修改

//省略上面相同代码......// 修改记录var conditions = {name : 'java'};var update     = {$set : {age : 27}};var options    = {upsert : true};vipModel.update(conditions, update, options, function(error){    if(error) {        console.log(error);    } else {        console.log('update ok!');    }    //关闭数据库链接    db.disconnect();});

4.删除

删除有2种方式,Entity和Model都使用remove方法

//省略上面相同代码......var conditions = {username: 'java'};vipModel.remove(conditions, function(error){    if(error) {        console.log(error);    } else {        console.log('delete ok!');    }    //关闭数据库链接    db.disconnect();});

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    });

4.1 查询子文档

如果children是parent的子文档,可以通过如下方法查询到children

var child = parent.children.id(id);

4.2 新增、删除、更新

子文档是父文档的一个属性,因此按照属性的操作即可,不同的是在新增父类的时候,子文档是会被先加入进去的。

如果ChildrenSchema是临时的一个子文档,不作为数据库映射集合,可以这样:

var ParentSchema = new Schema({   children:{      name:String   }});//其实就是匿名混合模式

数据验证

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

  • 验证始终定义在SchemaType中
  • 验证是一个内部中间件
  • 验证是在一个Document被保存时默认启用的,除非你关闭验证
  • 验证是异步递归的,如果你的SubDoc验证失败,Document也将无法保存
  • 验证并不关心错误类型,而通过ValidationError这个对象可以访问
    7.1 验证器
  • 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是验证失败的错误信息      }    });

7.2 验证失败

如果验证失败,则会返回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属性。

Model至Collection的命名策略

mongoose/lib/util.js模块中如下代码片段是集合命名的根源。

function pluralize (str) {  var rule, found;  if (!~uncountables.indexOf(str.toLowerCase())){    found = rules.filter(function(rule){      return str.match(rule[0]);    });    if (found[0]) return str.replace(found[0][0], found[0][1]);  }  return str;};

1.判断模型名是否是不可数的,如果是直接返回模型名;否则进行复数转化正则匹配;

2.返回复数转化正则匹配结果(一个复数转化正则匹配是一个数组,有两个对象,[0]正则表达式,[1]匹配后处理结果);

3.如果复数转化正则匹配结果不存在,直接返回模型名;否则取匹配结果第一个,对模型名进行处理。(需要说明的是,rules是按特殊到一般的顺序排列的)

部分内容来自:http://ourjs.com/detail/53ad24edb984bb4659000013

0 0
原创粉丝点击