mongoose官网 http://mongoosejs.com/
1.Mongoose学习参考文档
前言:本学习参考文档仅供参考,如有问题,师请雅正
##一、快速通道
###1.1 名词解释
-
Schema
: 一种以文件形式存储的数据库模型骨架,不具备数据库的操作能力 -
Model
: 由Schema
发布生成的模型,具有抽象属性和行为的数据库操作对 -
Entity
: 由Model
创建的实体,他的操作也会影响数据库
注意:
1.本学习文档采用严格命名方式来区别不同对象,例如:
var PersonSchema; //Person的文本属性
var PersonModel; //Person的数据库模型
var PersonEntity; //Person实体
2.Schema
、Model
、Entity
的关系请牢记,Schema
生成Model
,Model
创造Entity
,Model
和Entity
都可对数据库操作造成影响,但Model
比Entity
更具操作性。
##1.2 准备工作
2.在项目只能够创建一个数据库连接,如下:
var mongoose = require('mongoose'); //引用mongoose模块
var db = mongoose.createConnection('localhost','test'); //创建一个数据库连接
3.打开本机localhost
的test
数据库时,我们可以监测是否有异常
db.on('error',console.error.bind(console,'连接错误:'));
db.once('open',function(){
//一次打开记录
});
注意:
成功开启数据库后,就可以执行数据库相应操作,假设以下代码都在回调中处理
4.定义一个Schema
var PersonSchema = new mongoose.Schema({
name:String //定义一个属性name,类型为String
});
5.将该Schema
发布为Model
var PersonModel = db.model('Person',PersonSchema);
//如果该Model已经发布,则可以直接通过名字索引到,如下:
//var PersonModel = db.model('Person');
//如果没有发布,上一段代码将会异常
6.用Model
创建Entity
var personEntity = new PersonModel({
name:'Krouky'});
//打印这个实体的名字看看
console.log(personEntity.name); //Krouky
7.我们甚至可以为此Schema
创建方法
//为Schema模型追加speak方法
PersonSchema.methos.speak = function(){
console.log('我的名字叫'+this.name);
}
var PersonModel = db.model('Person',PersonSchema);
var personEntity = new PersonModel({
name:'Krouky'});
personEntity.speak();//我的名字叫Krouky
8.Entity
是具有具体的数据库操作CRUD
的
personEntity.save(); //执行完成后,数据库就有该数据了
9.如果要执行查询,需要依赖Model
,当然Entity
也是可以做到的
PersonModel.find(function(err,persons){
//查询到的所有person
});
注意:
1. 具体的如何配置Schema
、Model
以及Model
和Entity
的相关操作,我们会在后面进行
2. Model
和Entity
都有能影响数据库的操作,但仍有区别,后面我们也会做解释
##二、新手指引
如果您还不清楚Mongoose
是如何工作的,请参看第一章快速通道快速浏览他的用法吧
###1. Schema——纯洁的数据库原型
####1.1 什么是Schema
- 我理解
Schema
仅仅只是一断代码,他书写完成后程序依然无法使用,更无法通往数据库端 - 他仅仅只是数据库模型在程序片段中的一种表现,或者是数据属性模型
####1.2 如何定义Schema
var BlogSchema = new Schema({
title:String,
author:String
//new Schema()中传入一个JSON对象,该对象形如 xxx:yyyy ,
/xxx是一个字符串,定义了属性,yyy是一个Schema.Type,定义了属性类型
});
####1.3 什么是Schema.Type
Schema.Type
是由Mongoose
内定的一些数据类型,基本数据类型都在其中,他也内置了一些Mongoose
特有的Schema.Type
。当然,你也可以自定义Schema.Type
,只有满足Schema.Type
的类型才能定义在Schema
内。
####1.4 Schema.Types
NodeJS
中的基本数据类型都属于Schema.Type
,另外Mongoose
还定义了自己的类型
//举例:
var ExampleSchema = new Schema({
name:String,
binary:Buffer,
living:Boolean,
updated:Date,
age:Number,
mixed:Schema.Types.Mixed, //该混合类型等同于nested
_id:Schema.Types.ObjectId, //主键
_fk:Schema.Types.ObjectId, //外键
array:[],
arrOfString:[String],
arrOfNumber:[Number],
arrOfDate:[Date],
arrOfBuffer:[Buffer],
arrOfBoolean:[Boolean],
arrOfMixed:[Schema.Types.Mixed],
arrOfObjectId:[Schema.Types.ObjectId]
nested:{
stuff:String,
}
});
####1.5 关于Buffer
Buffer
和ArrayBuffer
是Nodejs
两种隐藏的对象,相关内容请查看NodeJS-API
####1.6 关于Mixed
Schema.Types.Mixed
是Mongoose
定义个混合类型,该混合类型如果未定义具体形式。因此,如果定义具体内容,就直接使用{}
来定义,以下两句等价
var AnySchema = new Schema({
any:{}});
var AnySchema = new Schema({
any:Schema.Types.Mixed});
混合类型因为没有特定约束,因此可以任意修改,一旦修改了原型,则必须调用markModified()
person.anything = {
x:[3,4,{
y:'change'}]}
person.markModified('anything');//传入anything,表示该属性类型发生变化
person.save();
####1.7 关于ObjectId
主键,一种特殊而且非常重要的类型,每个Schema
都会默认配置这个属性,属性名为_id
,除非自己定义,方可覆盖
var mongoose = require('mongoose');
var ObjectId = mongoose.Schema.Types.ObjectId;
var StudentSchema = new Schema({}); //默认会有_id:ObjectId
var TeacherSchema = new Schema({
id:ObjectId});//只有id:ObjectId
该类型的值由系统自己生成,从某种意义上几乎不会重复,生成过程比较复杂,有兴趣的朋友可以查看源码。
####1.8 关于Array
Array
在JavaScript
编程语言中并不是数组,而是集合,因此里面可以存入不同的值,以下代码等价:
var ExampleSchema1 = new Schema({
array:[]});
var ExampleSchema2 = new Schema({
array:Array});
var ExampleSchema3 = new Schema({
array:[Schema.Types.Mixed]});
var ExampleSchema4 = new Schema({
array:[{}]});
####1.9 附言
Schema
不仅定义了文档结构
和使用性能
,还可以有扩展插件
、实例方法
、静态方法
、复合索引
、文档生命周期钩子
Schema
可以定义插件,并且插件具有良好的可拔插性,请有兴趣的读者继续往后阅读或者查阅官方资料。
###2. Schema的扩展
####2.1 实例方法
有的时候,我们创造的Schema
不仅要为后面的Model
和Entity
提供公共的属性,还要提供公共的方法。
下面例子比快速通道的例子更加高级,可以进行高级扩展:
var PersonSchema = new Schema({
name:String,type:String});
//查询类似数据
PersonSchema.methods.findSimilarTypes = function(cb){
return this.model('Person').find({
type:this.type},cb);
}
使用如下:
var PersonModel = mongoose.model('Person',PersonSchema);
var krouky = new PersonSchema({
name:'krouky',type:'前端工程师'});
krouky.findSimilarTypes(function(err,persons){
//persons中就能查询到其他前端工程师
});
####2.2 静态方法
静态方法在Model
层就能使用,如下:
PersonSchema.statics.findByName = function(name,cb){
this.find({
name:new RegExp(name,'i'),cb});
}
var PersonModel = mongoose.model('Person',PersonSchema);
PersonModel.findByName('krouky',function(err,persons){
//找到所有名字叫krouky的人
});
####2.3 索引
索引或者复合索引能让搜索更加高效,默认索引就是主键索引ObjectId
,属性名为_id
,索引会作为一个专题来讲解
####2.4 虚拟属性
Schema
中如果定义了虚拟属性,那么该属性将不写入数据库,例如:
var PersonSchema = new Schema({
name:{
first:String,
last:String
}
});
var PersonModel = mongoose.model('Person',PersonSchema);
var krouky = new PersonModel({
name:{
first:'krouky',last:'han'}
});
如果每次想使用全名就得这样
console.log(krouky.name.first + ' ' + krouky.name.last);
显然这是很麻烦的,我们可以定义虚拟属性
:
PersonSchema.virtual('name.full').get(function(){
return this.name.first + ' ' + this.name.last;
});
那么就能用krouky.name.full
来调用全名了,反之如果知道full,也可以反解first
和last
属性
PersonSchema.virtual('name.full').set(function(name){
var split = name.split(' ');
this.name.first = split[0];
this.name.last = split[1];
});
var PersonModel = mongoose.model('Person',PersonSchema);
var krouky = new PersonModel({});
krouky.name.full = 'krouky han';//会被自动分解
console.log(krouky.name.first);//krouky
####2.5 配置项
在使用new Schema(config)
时,我们可以追加一个参数options
来配置Schema
的配置,形如:
var ExampleSchema = new Schema(config,options);
或者使用
var ExampleSchema = new Schema(config);
ExampleSchema.set(option,value);
可供配置项有:safe
、strict
、capped
、versionKey
、autoIndex
#####2.5.1 safe——安全属性(默认安全)
一般可做如下配置:
new Schema({...},{
safe:true});
当然我们也可以这样
new Schema({...},{
safe:{
j:1,w