超详细的数据库mongoose的使用方法/教程

学东西肯定是先看下官网了:http://mongoosejs.com/

看下官网的实例代码

var mongoose = require('mongoose');
mongoose.connect('mongodb://localhost/test');

var Cat = mongoose.model('Cat', { name: String });

var kitty = new Cat({ name: 'Zildjian' });
kitty.save(function (err) {
if (err) {
console.log(err);
} else {
console.log('meow');
}
});

Mongoose提供了一个直观的,基于模式的解决方案来建模应用程序数据。它包括内置的类型转换,验证,查询构建,业务逻辑挂钩等,开箱即用;

是mongoDB的好基友;

为了保存网站的用户数据和业务数据,通常需要一个数据库MongoDBNode.js特别般配,因为mongodb是基于文档的非关系型数据库,文档是按BSON(JSON的轻量化二进制格式)存储的,增删改查等管理数据库的命令和JavaScript语法很像。如果你在node.js里访问MongoDB的数据,会有我们是一家人的感觉,特别亲切。

MongoDB使用集合(collection)和文档(document)来描述和存储数据,collection就相当于表,document相当于行,不过MySQL之类的关系型数据库,表结构是固定的,比如某一行由若干列组成,行行都一样,而MongoDB不同,一个集合里的多个文档可以有不同的结构,更灵活一些。

Mongoose Web Server是一款易于使用的Web服务器,它可以嵌入到其它应用程序中,为其提供Web接口。

主要特写:

  • 跨平台,支持 Windows、OS X 和 Linux

  • 支持 CGI, SSL, SSI, Digest (MD5) 认证,WebSocket 和 WebDAV

  • 支持断点续传和 URL 重写

  • 基于 IP 的 ACL,支持 Windows 服务,支持 GET, POST, HEAD, PUT, DELETE 方法

  • Excluding files from serving by URI pattern

  • 下载速度限制,基于客户端子网和 URI 模式

  • 体积小,可执行文件只有 40k 左右

  • 可嵌入式,提供简单的 API (mongoose.h). 只需一个源码文件 mongoose.c

  • 嵌入式实例: hello.c, post.c, upload.c, websocket.c

  • 提供 Python 和 C# 版本

  • 采用 MIT 授权协议

~~~~~~~~~~~~~

1. 基础介绍 #

1.1 MongoDB简介 #

MongoDB是一个开源的NoSQL数据库
同时它也是一个对象数据库,没有固定的模式和结构
所有的数据以文档的形式存储,数据格式就是JSON。

1.2 Mongoose是什么? #

Mongoose是MongoDB的一个对象模型工具
同时它也是针对MongoDB操作的一个对象模型库,封装了MongoDB对文档的的一些增删改查等常用方法
让NodeJS操作Mongodb数据库变得更加灵活简单

1.3 安装mongoose #

接下来使用npm从命令行安装Mongoose:

$ npm install mongoose

1.4 使用mongoose #

var mongoose = require("mongoose");
//mongoose.connect("mongodb://localhost:端口号/数据库名称");
mongoose.connect("mongodb://localhost:27017/xxxxxxx");

当然这也是不好的,还需要错误信息的啊

var db = mongoose.connection;
db.on('error', console.error.bind(console, 'connection error:'));
db.once('open', function (callback) {
// yay!
});

1.5 Schema #

Schema是数据库集合的模型骨架
定义了集合中的字段的名称和类型以及默认值等信息

1.5.1 Schema.Type #

NodeJS中的基本数据类型都属于 Schema.Type
另外Mongoose还定义了自己的类型
基本属性类型有:

  • 字符串(String)
  • 日期型(Date)
  • 数值型(Number)
  • 布尔型(Boolean)
  • null
  • 数组([])
  • 内嵌文档

1.5.2 定义Schema #

    var personSchema = new Schema({
      name:String, //姓名
      binary:Buffer,//二进制
      living:Boolean,//是否活着
      birthday:Date,//生日
      age:Number,//年龄
      _id:Schema.Types.ObjectId,  //主键
      _fk:Schema.Types.ObjectId,  //外键
      array:[],//数组
      arrOfString:[String],//字符串数组
      arrOfNumber:[Number],//数字数组
      arrOfDate:[Date],//日期数组
      arrOfBuffer:[Buffer],//Buffer数组
      arrOfBoolean:[Boolean],//布尔值数组
      arrOfObjectId:[Schema.Types.ObjectId]//对象ID数组
      nested:{ //内嵌文档
        name:String,
      }
    });
var mongoose = require('mongoose'),
    DB_URL = 'mongodb://localhost:27017/mongoosesample';

/**
 * 连接
 */
mongoose.connect(DB_URL);

/**
  * 连接成功
  */
mongoose.connection.on('connected', function () {    
    console.log('Mongoose connection open to ' + DB_URL);  
});    

/**
 * 连接异常
 */
mongoose.connection.on('error',function (err) {    
    console.log('Mongoose connection error: ' + err);  
});    
 
/**
 * 连接断开
 */
mongoose.connection.on('disconnected', function () {    
    console.log('Mongoose connection disconnected');  
});    

module.exports = mongoose;

  下面我们定义一个user的Schema,命名为user.js

/**
 * 用户信息
 */
var mongoose = require('./db.js'),
    Schema = mongoose.Schema;

var UserSchema = new Schema({          
    username : { type: String },                    //用户账号
    userpwd: {type: String},                        //密码
    userage: {type: Number},                        //年龄
    logindate : { type: Date}                       //最近登录时间
});

1.6 Model #

Model是由通过Schema构造而成
除了具有Schema定义的数据库骨架以外,还可以操作数据库
如何通过Schema来创建Model呢,如下:

//连接数据库
mongoose.connect("mongodb://123.57.143.189:27017/zfpx");
//两个参数表示定义一个模型
var PersonModel = mongoose.model("Person", PersonSchema);
// 如果该Model已经定义,则可以直接通过名字获取
var PersonModel = mongoose.model('Person');//一个参数表示获取已定义的模型

拥有了Model,我们也就拥有了操作数据库的能力

在数据库中的集合名称等于 模型名转小写再转复数,比如 Person>person>people,Child>child>children

1.7 Entity简述 #

通过Model创建的实体,它也可以操作数据库
使用Model创建Entity,如下示例:

 var personEntity = new PersonModel({
     name : "zfpx",
     age  : 6
 });

Schema生成Model,Model创造Entity,Model和Entity都可对数据库操作,但Model比Entity可以实现的功能更多

1.8 保存Entity #

var mongoose = require("mongoose");
mongoose.connect("mongodb://123.57.143.189:27017/zfpx");
var PersonSchema = new mongoose.Schema({
    name: {type: String},
    age: {type: Number, default: 0}
});
var PersonModel = mongoose.model("Person", PersonSchema);

var PersonEntity = new PersonModel({
    name: "zfpx",
    age: 6
});

PersonEntity.save(function (error, doc) {
    if (error) {
        console.log("error :" + error);
    } else {
       //doc是返回刚存的person对象 
        console.log(doc);
    }
});

1.9 ObjectId #

存储在mongodb集合中的每个文档都有一个默认的主键_id
这个主键名称是固定的,它可以是mongodb支持的任何数据类型,默认是ObjectId 该类型的值由系统自己生成,从某种意义上几乎不会重复
ObjectId是一个12字节的 BSON 类型字符串。按照字节顺序,依次代表:

  • 4字节:UNIX时间戳
  • 3字节:表示运行MongoDB的机器
  • 2字节:表示生成此_id的进程
  • 3字节:由一个随机数开始的计数器生成的值

每一个文档都有一个特殊的键_id,这个键在文档所属的集合中是唯一的。

1.10 为Entity增加实例方法 #

//注意此语句要写在定义PersonSchema之后,定义PersonModel之前
PersonSchema.methods.findSameAge = function(cb){
    //先获取模型 再调用find 把条件传入,调用回调
    this.model('Person').find({age:this.age},cb);
}
var PersonModel = db.model("person", PersonSchema);
 var PersonEntity = new PersonModel({
     name : "zfpx",
     age  : 6
 });
 PersonEntity.findSameAge(function(err,docs){
    console.log(docs);
 });

1.11 为Model增加静态方法 #

PersonSchema.statics.findByName = function(name,cb){
    this.find({name:new RegExp(name,'i')},cb)
}
var PersonModel = mongoose.model('Person',PersonSchema);
PersonModel.findByName('zfpx',function(err,persons){
     console.log(persons);  //获得所有名称叫zfpx的人
});

1.12 验证器 #

验证器是指定在数据保存到数据库之前做的验证

  • required 非空验证
  • min/max 范围验证(边值验证)
  • enum/match 枚举验证/匹配验证
  • validate 自定义验证规则
var PersonSchema = new Schema({
      name:{
        type:'String',
        match:/^zfpx/,//必须符合正则
        required:true //姓名非空
      },
      age:{
        type:'Nunmer',
        min:18,       //年龄最小18
        max:110     //年龄最大110
      },
      gender:{
        type:'String',
        enum:['男','女']  //只能是男或女
      },
      home{
        type:String,
        validate: [validator,'必须是北京']
      }
    });
    //自定义验证函数
    function validator (val) {
        return val == '北京';
    }

1.13 中间件 #

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

1.13.1 Serial串行 #

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

PersonSchema.pre('save',function(next){
     setTimeout(()=>{
        this.age = this.age * 2; //this 指向 entity
        next();
     },5000)
});

1.13.1 Parallel并行 #

schema.pre('save',function(next,done){
      //先继续执行下一个中间件
      next();
      //调用done表示本次中间件执行完毕,只有所有的中间件都执行完毕之后才意味着保存结束
      doAsync(done);
});

2. 基础操作 #

2.1 查询 #

语法

Model.find(查询条件,callback);

代码

Model.find({},function(error,docs){
  //若没有向find传递参数,默认的是显示所有文档
});

Model.find({ "age": 6 }, function (error, docs) {
  if(error){
    console.log("error :" + error);
  }else{
    console.log(docs); //docs: age为6的所有文档
  }
});

2.2 Model保存 #

语法

Model.create(文档数据, callback))

代码

 PersonModel.create({ name:"zfpx", age:7}, function(error,doc){
    if(error) {
        console.log(error);
    } else {
        console.log(doc);
    }
});

2.3 Entity保存 #

语法

Entity.save(callback))

代码

var PersonEntity = new PersonModel({name:"zfpx",age: 9});

PersonEntity.save(function(error,doc) {
   if(error) {
      console.log(error);
   } else {
      console.log(doc);
   }
});

2.4 更新 #

语法

Model.update(查询条件,更新对象,callback);

代码

var conditions = {name : 'zfpx'};
  var update = {$set : { age : 100 }};
  PersonModel.update(conditions, update, function(error){
      if(error) {
          console.log(error);
      } else {
          console.log('Update success!');
        }
    });

请注意如果匹配到多条记录,默认只更新一条,如果要更新匹配到的所有记录的话需要加一个参数 {multi:true}

2.5 删除 #

语法

Model.remove(查询条件,callback);

代码

var conditions = { name: 'zfpx' };
PersonModel.remove(conditions, function(error){
    if(error) {
          console.log(error);
    } else {
        console.log('Delete success!');
    }
});

3. 基本查询 #

3.1 准备数据 #

        PersonModel.create([
                          { name:"zfpx1", age:1 },
                          { name:"zfpx2", age:2 },
                          { name:"zfpx3", age:3 },
                          { name:"zfpx4", age:4 },
                          { name:"zfpx5", age:5 },
                          { name:"zfpx6", age:6},
                          { name:"zfpx7", age:7 },
                          { name:"zfpx8", age:8 },
                          { name:"zfpx9", age:9},
                          { name:"zfpx10",age:10 }
                         ], function(error,docs) {
            if(error) {
                console.log(error);
            } else {
                console.log('save ok');
            }
        });

3.2 属性过滤 #

语法

find(Conditions,field,callback)

代码

//field省略或为Null,则返回所有属性。
//返回只包含name、age两个键的所有记录
Model.find({},{name:1, age:1, _id:0},function(err,docs){
   //docs 查询结果集
})

我们只需要把显示的属性设置为大于零的数就可以,当然1是最好理解的,_id是默认返回,如果不要显示加上(“_id”:0)

3.3 findOne(查询单条) #

与find相同,但只返回单个文档,也就说当查询到即一个符合条件的数据时,将停止继续查询,并返回查询结果
语法

findOne(Conditions,callback)

代码

TestModel.findOne({ age: 6}, function (err, doc){
       // 查询符合age等于6的第一条数据
       // doc是查询结果
});

3.4 findById(按ID单条数据) #

与findOne相同,但它只接收文档的_id作为参数,返回单个文档
语法

findById(_id, callback)

代码

PersonModel.findById(person._id, function (err, doc){
     //doc 查询结果文档
});

3.5 $gt、$lt(大于、小于) #

查询时我们经常会碰到要根据某些字段进行条件筛选查询,比如说Number类型,怎么办呢,我们就可以使用$gt(>)、$lt(<)、$lte(<=)、$gte(>=)操作符进行排除性的查询,如下示例:

Model.find({"age":{"$gt":6}},function(error,docs){
   //查询所有nage大于6的数据
});

Model.find({"age":{"$lt":6}},function(error,docs){
   //查询所有nage小于6的数据
});

Model.find({"age":{"$gt":6,"$lt":9}},function(error,docs){
  //查询所有nage大于6小于9的数据
});

3.6 $ne(不等于) #

$ne(!=)操作符的含义相当于不等于、不包含,查询时我们可通过它进行条件判定,具体使用方法如下:

Model.find({ age:{ $ne:6}},function(error,docs){
  //查询age不等于6的所有数据
});

3.7 $in(包含) #

和$ne操作符相反,$in相当于包含、等于,查询时查找包含于指定字段条件的数据

Model.find({ age:{ $in: 6}},function(error,docs){
   //查询age等于6的所有数据
});

Model.find({ age:{$in:[6,7]}},function(error,docs){
  //可以把多个值组织成一个数组
});

3.8 $or(或者) #

可以查询多个键值的任意给定值,只要满足其中一个就可返回,用于存在多个条件判定的情况下使用,如下示例:

Model.find({"$or":[{"name":"zfpx"},{"age":6}]},function(error,docs){
    //查询name为zfpx或age为6的全部文档
});

3.9 $exists(是否存在) #

$exists操作符,可用于判断某些关键字段是否存在来进行条件查询。如下示例:

Model.find({name: {$exists: true}},function(error,docs){
      //查询所有存在name属性的文档
});

Model.find({email: {$exists: false}},function(error,docs){
      //查询所有不存在email属性的文档
});

4. 高级查询 #

可以限制结果的数量,跳过部分结果,根据任意键对结果进行各种排序

所有这些选项都要在查询被发送到服务器之前指定

4.1 limit(限制数量) #

在查询操作中,有时数据量会很大,这时我们就需要对返回结果的数量进行限制
那么我们就可以使用limit函数,通过它来限制结果数量。
语法

find(Conditions,fields,options,callback);

代码

Model.find({},null,{limit:20},function(err,docs){
        console.log(docs);
});

如果匹配的结果不到20个,则返回匹配数量的结果,也就是说limit函数指定的是上限而非下限

4.2 skip(跳过/略过的数量) #

skip函数的功能是略过指定数量的匹配结果,返回余下的查询结果
如下示例:

find(Conditions,fields,options,callback);

代码

Model.find({},null,{skip:4},function(err,docs){
        console.log(docs);
});

如果查询结果数量中少于4个的话,则不会返回任何结果。

4.3 sort函数 #

sort函数可以将查询结果数据进行排序操作
该函数的参数是一个或多个键/值对
键代表要排序的键名,值代表排序的方向,1是升序,-1是降序
语法

find(Conditions,fields,options,callback)

代码

 Model.find({},null,{sort:{age:-1}},function(err,docs){
      //查询所有数据,并按照age降序顺序返回数据docs
});

sort函数可根据用户自定义条件有选择性的来进行排序显示数据结果。

4.4 分页查询 #

Model('User').find({})
  .sort({createAt:-1})
  .skip((pageNum-1)*pageSize)
  .limit(pageSize)
  .populate('user')
  .exec(function(err,docs){
     console.log(docs);
  });

4.5 populate #

var mongoose = require('mongoose');
//连接数据库
mongoose.connect('mongodb://localhost:27017/201606blog');
//定义课程Schema
var CourseSchema = new mongoose.Schema({
    name:String
});
var CourseModel = mongoose.model('Course',CourseSchema);
var PersonSchema = new mongoose.Schema({
    name:{
        type:String,
        required:true
    },
    // 外键 别的集合的主键
    course:{
        type:mongoose.Schema.Types.ObjectId,
        ref:'Course' //指明此外键是哪个集合中的外键
    }
});
var PersonModel = mongoose.model('Person',PersonSchema);
CourseModel.create({name:'node.js'},function(err,course){
    PersonModel.create({name:'zfpx',course:course._id},function(err,doc){
        console.log(doc);
        PersonModel.findById(doc._id).populate('course').exec(function(err,doc){
            console.log(doc);
        })
    })
});

4.6 __v 版本锁 #

当修改数组属性的时候要使用版本锁

var mongoose = require('mongoose');
mongoose.connect('mongodb://localhost:27017/201606blog');
var PersonSchema = new mongoose.Schema({
    name:{
        type:String,
        required:true
    },
    courses:[String]
});
var PersonModel = mongoose.model('Person',PersonSchema);
console.time('cost');
PersonModel.create({name:'zfpx'},function(err,doc){
    PersonModel.findById(doc._id,function(err,doc){
        doc.courses.push('node');
        setTimeout(function(){
            doc.save(function(err,doc){
                console.log(doc);
            });
        },5000);
    })

    PersonModel.findById(doc._id,function(err,doc){
        doc.courses.push('js');
        setTimeout(function(){
            doc.save(function(err,doc){
                console.log(doc);
                console.timeEnd('cost');
            });
        },10000);
    })
});

5. 扩展阅读 #

mongoose

其它操作

其它还有比较多常用的

索引和默认值

  再看看我对user.js这个schema的修改

/**
 * 用户信息
 */
var mongoose = require('./db.js'),
    Schema = mongoose.Schema;

var UserSchema = new Schema({          
    username : { type: String , index: true},                    //用户账号
    userpwd: {type: String},                        //密码
    userage: {type: Number},                        //年龄
    logindate : { type: Date, default:Date.now}                       //最近登录时间
});

module.exports = mongoose.model('User',UserSchema);

index :建索引

  default:默认值

LBS地址位置

lbs : { type: Array, index: '2d', sparse: true }   //地理位置

  上面有介绍过很多基于LBS的条件查询,Schema中定义时如上

  LBS查询对于一些基于LBS应用会用得比较多。

其它常用方法

  Model.distinct(field, [conditions], [callback])                  //去重

  Model.findOne(conditions, [fields], [options], [callback])             //查找一条记录

  Model.findOneAndRemove(conditions, [options], [callback])           //查找一条记录并删除

  Model.findOneAndUpdate([conditions], [update], [options], [callback])     //查找一条记录并更新

~~~~~

未经允许不得转载:WEB前端开发 » 超详细的数据库mongoose的使用方法/教程

赞 (14)