第一章 MongoDB简介
第一讲.数据库简介
数据库是按照数据结构来组织,存储和管理数据的仓库
我们的程序都是在内存中运行,一旦程序运行结束或者计算机断电,程序运行中的数据都会丢失
所以我们就需要将一些程序运行的数据持久化到硬盘中,以确保数据的安全性
而数据库可就是数据持久化的最佳选择
数据库的分类:
-
关系型数据库(如MySQL)
关系型数据库中全都是表
-
非关系型数据库(如MongoDB)
使用的不是SQL语言
非关系型数据库中是键值对数据库或者文档数据库
MongoDB始为快速开发互联网Web应用而设计的数据库系统
MongoDB的设计目标是极简,灵活,作为Web应用栈的一部分
MongoDB的数据模型是面向文档的,所谓的文档指的是一种类似于JSON的结构
可以理解为MondoDB存储的是各种各样的JSON(BSON)
第二讲.MongoDB的基本操作
三个概念:
-
数据库database
是数据存储的仓库,在其中可以存放集合
-
集合collection
类似于数组,在集合中可以存放文档
-
文档document
文档数据库中的最小单位,我们存储和操作的内容都是文档
MongoDB直接操作的就是文档
在MongoDB中,database和collection都不需要手动创建,当我们第一次向数据库中插入文档时,数据库会自动创建
基本指令:
-
show dbs
显示当前所有的数据库
-
use 数据库名
进入指定的数据库
-
db
显示当前所在的数据库名,优点类似于this
-
show collections
查看数据库中有多少个集合
第二章 数据库的操作
第一讲.插入文档
数据库的CRUD(增删改查)操作:
插入
在集合中插入一个文档
db.<collection>.insert(doc)
collection指的是集合名,doc是文档
例:向test数据库的stus集合中插入一个新的学生对象
{name:"liu",age:18,gender:"male"}
写法:
db.stus.insert({name:"liu",age:18,gender:"male"})
插入多个文档就是传递一个数组
db.stus.insert([
{name:"liu",age:18,gender:"male"},
{name:"wang",age:19,gender:"female"},
{name:"zhang",age:20,gender:"male"},
]);
当我们向集合中插入文档时,如果没有给文档指定_id
那么mongodb会自动为文档添加_id,作为文档的唯一标识
如果自己指定_id,数据库就不会再自动添加,但是我们要确保它的唯一性
另外有两个拆分的方法:
-
插入一个文档
只能传递一个对象
db.collection.insertOne();
-
插入多个文档
只能传递一个数组
db.collection.insertMany();
第二讲.查询文档
查询集合中的所有文档
db.<collection>.find()
如:
db.stus.find();
在find( )中,可以传递参数作为条件参数,查询符合条件的文档,返回的是一个数组
如果不写条件,或者传一个空对象,都表示查询所有文档
格式 {字段名:值} 如:
db.stus.find({_id:'hello'});
也可以传递多个参数,使用逗号连接:
db.stus.find({_id:'hello',age:18});
同样有另外两个查询:
-
查询符合条件的第一个文档
返回的是一个文档对象
db.collection.findOne();
-
查询符合条件的文档个数
db.collection.find({}).count();
第三讲.修改文档
将指定的对象修改为新对象
db.collection.update(查询对象,新对象);
如:
db.stus.update({name:'沙和尚',{age:28}})
update默认情况下会使用新对象替换旧对象
如果需要修改指定的属性而不是替换,需要使用修改操作符:
$set用来修改文档中的指定属性
db.inventory.updateOne(
{name:'沙和尚'},
{$set:{
age:28,
gender:'male'
}}
)
$unset用于删除文档的指定属性
db.inventory.updateOne(
{name:'沙和尚'},
{$unset:{
age:28
}}
)
update默认情况下只修改看到的第一个对象,如果有多个,就要添加第三个参数:
multi,默认为false,表示只修改一个,改为true以后可以修改所有的
db.inventory.updateOne(
{name:'沙和尚'},
{$set:{
age:28,
gender:'male'
}},
{
multi:true
}
)
另外两个方法:
-
同时修改多个符合条件的文档
db.collection.updateMany();
-
修改一个符合条件的文档
db.collection.updateOne();
第四讲.删除文档
删除符合条件的文档
参数为对象形式的条件
db.collection.remove();
如:
db.stus.remove({_id:'hello'});
默认会删除符合条件的所有文档,如果想只删除一个文档,需要设置第二个参数
将第二个参数设置为true,即可只删除一个
db.stus.remove( {_id:'hello'}, true);
如果指定条件设置为空对象,则会删除集合中的所有文档
另外的方法:
-
如果想删除一个集合
db.collection.deleteOne();
-
如果想删除多个集合
db.collection.deleteMany();
删库跑路
如果想删除数据库
db.dropDatabase();
但是数据库一般都不会删除,这个方法很少调用
如果真的想删除,也只是在数据中添加一个字段,表明是否被删除,然后以后查询时,只看字段为指定值的内容
第五讲.练习一
-
进入my_test数据库
use my_test;
-
向数据库的user集合中插入一个文档
db.users.insert({name:'liu',age:18});
-
查询user集合中的文档
db.users.find();
-
再次插入文档
db.users.insert({name:'wang',age:20});
-
统计users集合中的文档数量
db.users.find().count();
-
查询users集合中name为liu的文档
db.users.find({name:'liu'});
-
向users集合中name为liu的文档中加入一个address属性,属性值为hangzhou
db.users.update( {name:'liu'}, {$set:{ address:'hangzhou' }} )
-
使用{name:‘li’,age:25}替换{name:‘wang’,age:20}的文档
db.users.replaceOne({name:'wang'},{name:'li',age:25});
-
删除name为liu的文档的address属性
db.users.update({name:'liu'},{$unset:{arrdess:1}});
-
向liu中添加一个hobby:{cicies:{[‘beijing’,‘tianjin’,''shanghai]}}
MongoDB的文档的属性值也可以是一个文档
当一个文档的属性值为一个文档时,这个文档称为内嵌文档
db.users.update( {name:'liu'}, {$set:{ hobby:{ cicies:['beijing','tianjin','shanghai'], movies:['a','b','c'] } }} );
-
查询movies
mongodb支持直接通过内嵌文档的属性进行查询,直接用js中对象的语法就可以
如果要通过内嵌文档进行查询,则属性名必须使用引号db.users.find({"hobby.movies":'a'});
-
向liu中添加一个新电影d
$push操作符:向数组中加入指定的元素
db.users.update({name:'liu'},{$push:{"hobby.movies":'d'}});
$addToSet操作符:向数组中添加一个没有的新元素(如果已经有了,就不添加)
db.users.update({name:'liu'},{$addToSet:{"hobby.movies":'d'}});
-
删除age为25的用户
db.users.remove({age:25});
-
删除users集合
db.users.remove({});
-
向number中插入20000条数据
我们采用的方式是将多个数据合并成一个数组,添加一次,而不是每次添加一个数据,添加多次
是因为每次访问数据库要消耗大量的时间,我们应尽量减少对数据库的访问
var arr=[]; for(var i=1;i<20000;i++){ arr.push({num:i}); } db.number.insert(arr);
可以在mongo中使用js语句
第六讲.练习二
一些操作符:
-
$eq,等于
//查询numbers中num为500的文档 db.number.find({num:500});
-
$gt,大于
//查询numbers中num大于500的文档 db.number.find({num:{$gt:500}});
-
$gte大于等于
//查询numbers中num大于等于500的文档 db.number.find({num:{$gte:500}});
-
$lt小于
//查询numbers中num小于30的文档 db.number.find({num:{$lt:30}});
-
$lte小于等于
//查询numbers中num小于等于30的文档 db.number.find({num:{$lte:30}});
-
$ne不等于
如果有多个条件要同时满足,中间用逗号连接
db.number.find({num:{$gt:500,$lt:1000}});
如果有多个条件,满足其中的一个,则用$or指明每个条件
db.number.find({
$or:[
{num:{$lt:1000}},
{num:{$gt:2000}}
]
});//大于2000或小于1000
关于页码:
-
查询numbers中n的前十个数据
db.number.find().limit(10);
-
查询numbers中num第十一到二十个数据
分页:每页十条,第二页是11-20条
skip用于跳过指定数量的数据
因此,应有如下的格式:skip((页码-1)*每页显示的条数).limit(每页显示的条数)db.number.find().skip(10).limit(10);
第七讲.文档间的关系
一个数据库中往往不只有一个集合
文档间的关系主要分三种:
-
一对一(one to one)
夫妻(一个丈夫对应一个妻子)
在mongoDB中,通过内嵌文档的形式展现一对一的关系
db.wifeAndHusband.insert([ {name:'黄蓉',husband:{name:'郭靖'}} {name:'潘金莲',husband:{name:'武大郎'}} ])
实际开发中应用的不多
-
一对多(one to many)
使用的最多,用户和订单
db.user.insert([ {user:'swk',_id:'001'}, {username:'zbj',_id:'002'} ]) db.order.insert({ list:['a','b','c'], user_id:'001'//添加的是swk的id,以此来体现订单的归属 })
查找swk的订单:
var id=db.users.findOne({username:'swk'})._id; db.order.find({user_id:id});
-
多对多(many to many)
分类和商品,一个分类有多个商品,一个商品也可以属于多个分类
db.teachers.insert([ {name:'洪七公',_id:'001'}, {name:'黄药师',_id:'002'}, {name:'龟仙人',_id:'003'} ]) db.stus.insert([ { name:'郭靖', tech_ids:['001','002'] } { name:'孙悟空', tech_ids:['001','002','003'] } ])
第八讲.sort和投影
当我们在查询文档时,数据默认按照id进行升序排序
如果我们不想按照id排序,而是按照我们想的某一列去排序,怎么办?
于是引入了sort( )方法,指定排序的规则
sort中需要需要传递一个对象用于指定排序规则
对象的属性名为按照哪一列排序,属性值为1或-1,表示升序或者降序
db.emp.find().sort({sal:1});
如果同时指定多个值,则是按照第一个属性先排序,第一个属性一样的,按照第二个属性排序
db.emp.find().sort({sal:1,empno:-1});
在查询时,我们不一定想要所有的文档数据,可能只想要某些列
这时我们可以在第二个参数的位置来设置查询结果的投影
id默认情况下都有,不想要需要单独设置,属性名表示希望显示哪一列,属性值为1表示显示,0表示不显示
db.emp.find({},{ename:1,_id:0,sal:1})
第三章 Mongoose
第一讲.Mongoose简介
是node里面的模块,有了它,可以通过node操作MondoDB的模块
Mondoose是一个对象文档模型库,它对Node原生的MongoDB模块进行了进一步的优化和封装
让我们更好的以面向对象的形式操作数据库
Mongoose的好处:
- 可以为文档创建一个模式结构(或称为约束)
- 可以对模型中的对象/文档进行验证
- 数据可以通过类型转换转换为对象模型
- 可以使用中间件来应用业务逻辑结构
- 比Node原生的MongoDB驱动更容易
Mongoose中为我们提供了几个新对象:
-
Schema(模式对象)
Schema对象定义了约束数据中的文档结构
-
Model
Model对象作为集合中的所有文档的表示,相当于MongoDB数据库中的集合collection
-
Document
Document表示集合中的具体文档,相当于集合中的一个具体的文档
这三个对象的创建是有顺序的,必须依次创建
使用Mongoose的步骤
-
下载
npm i mongoose --save
-
在项目中引入mongoose
var mongoose=require('mongoose');
-
连接mongoDB数据库
一般只需要连接一次,除非项目停止,服务器关闭,否则不会调它
格式:
mongoose.connect('mongodb://主机号:端口号/数据库名',{useMongoClient:true});
如果端口号是默认端口号(27017),则可以省略不写
-
监听数据库的连接状态
在mongoose对象中,有一个属性叫做connection,表示的是数据库连接
通过监视该对象的状态,可以监听数据库的连接与断开
//数据库连接成功的事件 mongoose.connection.once('open',function(){}); //数据库断开的事件 mongoose.connection.once('close',function(){});
-
断开数据库连接
一般不需要它
mongoose.disconnect();
第二讲.Schema
使用方法:
在数据库连接成功后,才可以创建Schema对象
步骤:
-
讲mongoose.Schema赋值给一个变量
var Schema=mongoose.Schema;
-
创建Schema对象
var stuSchema=new Schema({ name:String, age:Number, address:String gender:{//如果要配置一个复杂的内容,后面传递的应该是对象 type:String, default:'female'//默认值 } })
-
通过Schema创建model
Model代表的是数据库中的集合,通过Model才能对数据库进行操作
第一个参数是modelName,就是我们要映射的集合名
var StuModel=mongoose.model('student',strSchema);
-
向数据库中插入文档
两个参数:
- 插入的文档
- 回调函数
StuModel.create({ name:'liu', age:18, gender:'male', address:'hangzhou' },function(err){ if(!err) console.log('插入成功'); });
注意:mongoose会自动将集合名变成复数
第三讲.Model
上一讲的所有内容,都是在创建一个Model
有了Model我们就可以来对数据库进行增删改查的操作了
-
增
Model.create(docs,[callback])
创建一个或多个文档并添加到数据库中
参数:
- docs 可以是一个或多个对象,也可以是一个对象的数组
- callback 当操作完成以后调用的回调函数
StuModel.create({ name:'liu', age:18, gender:'male', address:'hangzhou' },function(err){ if(!err) console.log('插入成功'); });
-
查
有以下几个方法:
-
Model.find(condentions,[projection],[options],callback)
查询所有符合条件的文档
-
Model.findById(id,[projection],[options],callback)
根据Id查询文档
-
Model.findOne(condentions,[projection],options],callback)
查询符合条件的第一个文档,返回的不是数组,而是一个具体的文档对象
属性:
-
condentions 查询的条件
-
projection 投影,需要获取到的字段
字符串类型,想要什么属性就写什么属性名,不想要的话就写 -属性名
-
options 查询选项
常用skip和limit两个参数
-
callback 回调函数,查询结果会通过回调函数返回
回调函数在这里必须传,如果不传回调函数,就根本不会查询
回调函数里面有两个参数:
- err
- docs 查询到的对象,返回的永远是一个数组,id查询除外
StuModel.find({name:'liu'},"name age -id",{skip:3,limit:1},function(err,docs){ if(!err) console.log(docs[0]) });
返回的对象是创建集合所用的model的实例
-
-
改
与查找类似,具体的方法有:
- Model.update(condentions,doc,[options],callback)
- Model.updateMany(condentions,doc,[options],callback)
- Model.updateOne(condentions,doc,[options],callback)
用于修改一个或多个文档
参数:
- conditions 查询对象
- doc 修改后的对象
- options 配置参数
- callback 回调函数
StuModel.updateOne({name:'liu'},{$set:{age:20}},function(err){ if(!err) console.log('修改成功'); });
-
删
具体的方法有:
- Model.remove(conditions,[callback])
- Model.deleteOne(conditions,[callback])
- Model.deleteMany(conditions,[callback])
StuModel.remove({name:'liu'},function(err){ if(!err) console.log('删除成功'); })
一般不用
第四讲.Document
Document和集合中的文档是一一对应的
Document是Model的实例,通过Model查询到的结果都是Document
创建一个Document
var stu=new StuModel({
name:'wang',
age:20,
address:'北京',
gender:'male'
});
Document方法:
-
增
将document存入数据库
方法: document.save(callback)
stu.save(function(err){ if(!err) console.log('保存成功'); })
-
改
修改对象
方法:update(update,[options],[callback])
被修改的对象就是被调用的对象本身
doc.update({$set:{age:28}},function(err){ if(!err) console.log('修改成功'); })
最简单的方法,不写函数,直接修改属性值
doc.age=18; doc.save();
-
删
删除对象
doc.remove(function(err){ console.log('删除成功'); })
-
get和set
方法: get(属性值)
获取文档中的指定属性值
console.log(doc.get('name'));
方法: set(属性值)
设置文档的指定的属性值
doc.set('name','wang'); doc.save();
-
获取id属性值
console.log(doc._id);
第五讲.mongoose模块化
我们操作数据库所用的都是Model,前面的一长串都要来回复制
var mongoose=require('mongoose');
mongoose.connect('mongodb://127.0.0.1/mongoose_test');
mongoose.connection.once('open',function (){
console.log('数据库连接成功');
});
mongoose.connection.once('close',function (){
console.log('数据库已经断开');
})
var Schema=mongoose.Schema;
var stuSchema=new Schema({
name:String,
age:Number,
address:String,
gender:{
type:String,
default:'female'
}
});
var StuModel=mongoose.model('student',stuSchema);
就是上面这些,于是我们可以将其设置为一个模块
步骤:
-
定义一个模块,用来连接MongoDB数据库
var mongoose=require('mongoose'); mongoose.connect('mongodb://127.0.0.1/mongoose_test'); mongoose.connection.once('open',function (){ console.log('数据库连接成功'); });
-
然后在另一个文件中想使用数据库,只需要
require('./tools/conn_mongo');
由于不需要导入任何的参数,若以不需要接收变量
-
定义另一个模块,专门存放模型
var mongoose=require('mongoose'); //这里不需要连接数据库,因为这里是给别的模块用的,谁用谁连 var Schema=mongoose.Schema; var stuSchema=new Schema({ name:String, age:Number, address:String, gender:{ type:String, default:'female' } }); var StuModel=mongoose.model('student',stuSchema); module.exports=StuModel;//将模块暴露出去
-
接收模块
var Student=require('./models/student');