一、快速通道
1.1 名词解释
Schema : 一种以文件形式存储的数据库模型骨架,不具备数据库的操作能力
Model : 由Schema发布生成的模型,具有抽象属性和行为的数据库操作对
Entity : 由Model创建的实体,他的操作也会影响数据库
1.本学习文档采用严格命名方式来区别不同对象,例如:
```
var PersonSchema; //Person的文本属性
var PersonModel; //Person的数据库模型
var PersonEntity; //Person实体
Schema、Model、Entity的关系请牢记,Schema生成Model,Model创造Entity,Model和Entity都可对数据库操作造成影响,但Model比Entity更具操作性。、
二、使用mongoose的步骤
1.首先你必须安装MongoDB和NodeJS
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
});
Model和Entity都有能影响数据库的操作,但仍有区别,后面我们也会做解释
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内。
//举例:
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定义个混合类型,该混合类型如果未定义具体形式。因此,如果定义具体内容,就直接使用{}来定义,以下两句等价
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:[{}]});
- Schema的扩展
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.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;
});
三、查询语言系统
1、查询选择系统
最简单的查询语句,实现的是向数据库中插入20条数据
for(var i=1;i<11;i++)
{db.customers.insert({id:i,name:"小傲冥",age:100+i})}
找到对应的文档
db.customers.find({id:9})
为了精确的匹配选择器,条件可以是多个
db.customers.find({id:9,age:109})
带条件的查询
db.customers.find({age:{$lt:109}})
返回的是年龄小于109 的customer
lte小于或者等于
gt大于
gte大于或者等于
in key值在某些value的 $nin key值不在某些value的
db.customers.find({age:{$in:[103,105]}})
$or表示的是或运算选择器
db.customers.find({$or:[{id:1},{age:109}]})
$and表示的是与运算器
db.customers.find({$and:[{id:1},{age:109}]})
2、查询投射
查询选择器用来指定返回匹配的文档,有事我们需要对返回的结果进行进一步的处理,这时就使用到了查询投射
查询出来所有的字段并且对id字段进行排序
db.customers.find({}).sort({id:-1})
跳过10行,从这个位置返回接下来的5行,并且按id进行排序
db.customers.find({}).skip(5).limit(3).sort({id:-1})
3、数组操作
插入一个嵌套有数组的文档
db.customers.insert(
{"id":1,
"sta":[
{"sid":1,
"dec":"取消"},
{
"sid":2,
"dec":"已付款"}
]
})
四、索引与查询优化
mongoDB的索引的数据结构也是B+树,利用索引可以减少文档的扫描数量
单字段索引
建立一个唯一索引
db.customers.ensureIndex({name:1},{unique:true})
建立一个普通索引
db.customers.ensureIndex({name:1})
使用索引进行查询
db.customers.find({name:"aa9"}).explain()
演示索引的优点
for(var i=0;i<10;i++){
db.customers.insert({name:"aa"+i,country:"bb"})
}
使用索引,只会查找一篇文档
db.customers.find({"name":"aa9"}).explain()
db.customers.find({"country":"bb"}).explain()
没有使用索引、会查找所有的文档
复合索引
创建一个复合索引
db.customers.ensureIndex({name:1,country:1})
五、增删改操作
1、插入语句
db.customer.insert({name:"gyw",mobile:"1051743154"})
检测插入是成功
db.customer.find()
注意的是:不需要预先创建一个集合,插入时数据会自动创建,每一次创建的文档的_id都是必须唯一的,重复插入会引起错误
2、修改语句
由update来完成,mongo里边的修改分为两种
1、针对具体的目标字段
2、取代性的改变
update语句的语法格式:
db.collection.update({query,update,,})
query参数是一个查询器
update参数为需要修改的地方,若这个选项没有值的话,发生的就是取代性的变化
upsert 是一个可选参数 boolean 默认为false
为true的时候,当在记录没有找到匹配的时候会插入到文档的末尾。
multi 是一个可选参数 boolean 默认为false
为true的时候,当在记录中找到多条的记录的时候就会发生多条记录的替换,
演更新的操作
db.price.insert({name:"apple","price":3000})
实现更新的操作
1、更该指定的字段 name改为apple5s price加400
db.price.update({name:"apple"},{$set:{name:"apple5s"},$inc:{price:400}})
2、更改指定字段,其他字段被清除掉
db.price.update({name:"apple5s"},{name:"appleshausa"})
3、更改多个文档中的指定字段
db.price.update({name:"apple"},{$set:{price:5000}},{multi:true})
4、找不到文档时做插入的操作
db.price.update({name:"appleqwq"},{$set:{price:5000}},{upsert:true})
删除语句
mongoDB中的删除remove也是数据库CRUD操作中的一种最基本的操作
remove
格式:db.cllection.remove(,)
query:可选参数 类似于sql语句的where
justOne:可选参数 boolean 表示是否只是删除第一个,
remove()方法没有参数的时候表示删除所有的文档,氮素不会删除这个文档对应的索引。要删除集合的索引,使用的是drop方法