MongoDB是什么
MongoDB是一个基于分布式文件存储的数据库。有C++语言编写,旨在为WEB应用提供可扩展的高性能数据存储解决方案。
MongoDB是一个介于关系数据库和非关系数据库之间的产品,是非关系数据库当中功能最丰富,最像关系数据库的。
- 基于分布式文件存储数据库(就是一个数据库)
- C++语言编写
- 支持的数据结构非常松散,是类似json的bson格式(后期插入修改数据谢json)
json(JavaScript Object Notation,js对象简谱)是一种轻量级的数据交换格式
bson(二进制json)
MongoDB能干什么
- 存放项目数据
- 实战工作开发写API接口(重要)
MongoDB在win上的安装
步骤1:下载 http://www.mongodb.com/download-center/community
步骤2:解压
步骤3:创建服务(1. 必须通过管理员身份运行dos窗口,否则没有权限创建失败; 2. 要提前创建数据和日志存放的目录)
bin/mongod.exe --install --dbpath 磁盘目录 --logpath 日志目录
步骤4:启动服务
net start mongodb
步骤5:登录(验证是否安装成功)
MongoDB基本操作
查看数据库
语法:show databases
选择数据库
语法:use 数据库名
删除数据库
语法:
- 通过use语法选中数据库
- 通过
db.dropDatabase()
删除数据库
查看集合
语法:show collections
创建集合
语法:db.createCollection('集合名')
删除集合
语法:db.集合名.drop()
基操小总结
数据库(查看、创建、选择、删除)
查看:show databases
创建:有单独的语法,但是忽略 使用 use 数据库名 做隐式创建
选择:use 数据库名
删除:首先使用use选中数据库,然后通过db.dropDatabase()删除
1. use 数据库名
2. db.dropDatabase()
集合(查看、创建、删除)
查看:show collections
创建:db.createCollection('集合名') 忽略,后期插入数据,隐式创建集合
删除:db.集合名.drop()
MongoDB的增删改查
增
语法:db.集合名.insert(json数据)
说明:集合存在,则直接插入数据;集合不存在,则隐式创建集合后插入数据
练习:在test数据库中的c1集合中插入数据(名字较webopenfather年龄18岁)
use test
db.c1.insert({
name: 'webopenfather',
age: 18
})
留心1:数据库和集合不存在都隐式创建
留心2:对象的键统一不加引号,方便看,但是查看集合数据时系统自动加
留心3:mongodb会给每一条数据增加一个全球唯一的 _id 键
多学一招:_id的组成
思考1:是否可以自定义_id值?
回答:可以,只需要给插入的json数据中增加_id键即可覆盖(但实战强烈不推荐)
db.c1.insert(_id: 1, name: 'john', age: 18)
思考2:如何插入多条记录?
回答:传递数据,数组中写一个个json数据即可
db.c1.insert([ {name:'z3', age:3}, {name:'l4', age:4}, {name:'w5', age:5} ])
思考3:如何快速插入10条数据
回答: MongoDB底层使用js引擎实现的,所以支持一部分js语法,因此,可以使用for循环
for (var i=1; i<=10; i++) { print(i); } 需求:在test数据库的c2集合中插入10条数据,分别为a1 a2 ... a10 for (var i=1; i<=10; i++) { db.c2.insert(name:'a'+i, age:i) }
查
基础语法:db.集合名.find(条件 [,查询的列])
条件
查询所有数据 {}或者不写
查询age=6的数据 {age: 6}
查询age=6且性别为男 {age: 6, sex: '男'}
查询的列(可选参数)
不写 —— 这查询全部列(字段)
{age: 1} —— 只显示age列(字段)
{age: 0} —— 除了age列(字段)都显示
留心:不管怎么写,系统自定义的_id都会在
升级语法:
db.集合名.find({键: 值})
db.集合名.find({键: {运算符:值}})
运算符 | 作用 |
---|---|
$gt | 大于 |
$gte | 大于等于 |
$lt | 小于 |
$lte | 小于等于 |
$ne | 不等于 |
$in | in |
$nin | not in |
练习1:查询所有数据
use test
db.c2.find()
练习2:查询年龄大于5岁的数据
use test
db.c2.find({age: {$gt: 5}})
练习3:查询年龄是5岁、8岁、10岁的数据
use test
db.c2.find({age: {$in: [5, 8, 10]}})
练习4:只看年龄列,或者年龄以外的列(_id不管)
use test
db.c2.find({}, {age: 1}) 只看年龄列
use test
db.c2.find({}, {age: 0}) 不看年龄列
改
基础语法:db.集合名.update(条件, 新数据 [,是否新增, 是否修改多条])
是否新增:指条件匹配不到数据则插入 true是插入,false否不插入(默认)
是否修改多条:指将匹配成功的数据都修改(true是,false否(默认))
升级语法:
db.集合名.update(条件, 新数据)
{修改器: {键: 值}}
修改器 | 作用 |
---|---|
$inc | 递增 |
$rename | 重命名列 |
$set | 修改列值 |
$unset | 删除列 |
准备工作:
use test
for (var i=1; i<=10; i++) {
db.c3.insert({uname: 'zs'+i, age: i}
}
练习1:将{uname:"zs1"}改为{uname:"zs2"}
use test
db.c3.update({uname:'zs1'}, {uname:'zs2'})
-- 发生问题,默认整个都替换成了{uname:'zs2'},丢失了age数据;即默认为替换,不是修改,可以使用修改语法$set
正确代码:
use test
db.c3.update({uname: 'zs1'}, {$set: {uname: 'zs2'}})
练习2:给{uname:"zs10"}的年龄加2岁, 或减2岁
use test
db.c3.update({uname:'zs10'}, {$inc: {age: 2}}) 加2岁
use test
db.c3.update({uname:'zs10'}, {$inc: {age: -2}}) 减2岁
练习3:修改器综合练习
插入数据:db.c4.insert({uname:"神龙教主", age: 888, who: "男", other: "非国人"})
需求:
uname 改成 教主
age 增加 111
who 改字段 sex
other 删除
实现:
db.c4.update({uname: '神龙教主'}, { $set:{uname: '教主'}, $inc:{age: 111}, $rename:{who: 'sex'}, $unset:{other: 1}} ) db.c4.find().pretty()
练习4:验证语法的最后两个参数
-
是否新增:修改name等于zs30的年龄30岁
use test db.c3.find({uname: 'zs30'}, {$set: {age: 30}}, true)
-
是否修改多条
use test db.c3.find({}, {$set: {age: 20}}, false, true)
删
语法:db.集合名.remove(条件 [, 是否删除删除一条])
注意:是否删除一条参数,默认为false,即删除多条
小总结
增Create
db.集合名.insert(JSON数据)
删Delete
db.集合名.remove(条件 [,是否删除删除一条])
改Update
db.集合名.update(条件, 新数据 [,是否新增, 是否修改多条])
查Read
db.集合名.find(条件 [,查询的列])
MongoDB排序和分页
数据准备
use test
db.c1.insert({_id:1, name:"a", sex:1, age:1})
db.c1.insert({_id:2, name:"b", sex:1, age:2})
db.c1.insert({_id:3, name:"c", sex:2, age:3})
db.c1.insert({_id:4, name:"d", sex:2, age:4})
db.c1.insert({_id:5, name:"e", sex:2, age:5})
db.c1.find()
排序
语法:db.集合名.find().sort(JSON数据)
说明:键——就是要排序的列(字段);值:1 升序,-1降序
练习:年龄升序或降序
use test
db.c1.find().sort({age:1}) 升序
use test
db.c1.find().sort({age:-1}) 降序
limit和skip方法
语法:db.集合名.find().sort().skip(数字).limit(数字)
说明:skip跳过指定数量的数据,limit限制查询数据的数量
练习1:按降序查询,查询2条数据
use test
db.c1.find().sort({age:-1}).limit(2)
练习2:按降序查询,跳过2条然后查询2条数据
use test
db.c1.find().sort({age:-1}).skip(2).limit(2)
注意:skip和limit同时出现时,skip先执行,后执行limit,不管他们在语句中如何出现,即db.c1.find().sort({age:-}).limit(2).skip(2)和上面的效果一样
实战分页
需求:数据库1~10数据,每页显示2条(5页)
实现:
1页 1,2
2页 3,4
3页 5,6
4页 7,8
5页 9,10
skip计算公式:(当前页-1) * 每页显示条数
db.集合名.find().skip((page-1)*num_of_page).limit(2)
小总结
db.集合名.find()
.sort({列: 1/-1}) 排序
.skip(数字) 跳过指定数量
.limit(数字) 限制总数量
.count() 统计总数量
MongoDB聚合查询
语法:
db.集合名.aggregate([
{管道: {表达式}}
...
])
常用管道:
$group: 将集合中的文档分组,用于统计结果
$match: 过滤数据,输出符合条件的文档
$sort: 聚合数据进一步排序
$skip: 跳过指定文档数
$limit: 限制集合数据返回文档数
...
常用表达式:
$sum: 总和 $sum:1同count表示统计
$avg: 平均
$min: 最小值
$max: 最大值
...
数据准备
use test
db.c1.remove()
db.c1.insert({_id:1, name:"a", sex:1, age:1})
db.c1.insert({_id:2, name:"b", sex:1, age:2})
db.c1.insert({_id:3, name:"c", sex:2, age:3})
db.c1.insert({_id:4, name:"d", sex:2, age:4})
db.c1.insert({_id:5, name:"e", sex:2, age:5})
db.c1.find()
练习
-
统计男生、女生的总年龄
db.c1.aggregate([ { $group:{ _id: "$sex", re: {$sum: "$age"} } } ])
-
统计男生、女生的总人数
db.c1.aggregate([ { $group: { _id: "$sex", num: {$sum: 1} } } ])
-
求学生的总数和平均年龄
db.c1.aggregate([ { $group: { _id: null num: {$sum: 1}, avg_age: {$avg: "$age"} } } ])
-
查询男生、女生人数,按人数升序
db.c1.aggregate([ { $group: { _id: "$sex", rs: {$sum: 1} } }, { $sort: {rs: 1} } ])
MongoDB优化索引
数据库中的索引
- 说明:索引是一种排序好的便于快速查询的数据结构
- 作用:帮助数据库高效的查询数据
索引的优缺点
- 优点
- 提高数据查询的效率,降低数据库的IO成本
- 通过索引对数据进行排序,降低数据排序的成本,减低CPU的消耗
- 缺点
- 占用磁盘空间
- 大量索引影响sql语句效率,因为每次插入和修改数据都需要更新索引
语法
-
创建索引:
db.集合名.createIndex(待创建索引的列 [,额外选项])
参数:
-
待创建索引的列:{键: 1, ..., 键: -1}
说明:1表升序,-1表降序。例如{age:1}表示创建age索引并按照升序的方式存储
额外选项:设置索引的名称或者唯一索引等等
-
-
删除索引
全部删除:
db.集合名.dropIndexes()
删除指定:
db.集合名.dropIndex(索引名)
查看索引:
db.集合名.getIndexes()
练习
准备:向数据库中新增十万条数据
use test
for(var i=0; i<100000; i++) {
db.c1.insert({name:"aaa"+i, age:i})
}
创建普通索引
需求:给name添加普通索引
练习1:给name添加普通索引
db.c1.createIndex({name: 1})
练习2:删除name索引
db.c1.dropIndex('name_1')
练习3:给name创建索引起名name_index
db.c1.createIndex({name:1}, {name:"name_index"})
创建复合/组合索引
需求:给name和age添加组合索引
说明:就是一次性给两个字段建立索引
语法:
db.集合名.createIndex({键1: 方式1, 键2: 方式2})
db.createIndex({name:1, age:1})
创建唯一索引
需求:给name添加普通索引
语法:
db.集合名.createIndex(带添加索引的列, {unique: 列名})
练习1:删除全部索引
db.c1.dropIndexes()
练习2:设置唯一索引
db.c1.createIndex({name:1}, {unique:name})
测试唯一索引特性
对于唯一索引的列,它对应列的数据也必须唯一
分析索引
语法:
db.集合名.find().explain('executionStats')
-
练习
测试:age未添加索引的情况
db.c1.find({age:18}).explain('executionStats')
测试:age添加索引的情况
db.createIndex({age:1}) db.c1.find({age:18}).explain('executionStats')
选择规则(如何选择合适的列创建索引)
- 为常作条件、排序、分组的字段建立索引
- 选择唯一性索引
- 选择较小的数据列,为较长的字符串使用前缀索引
MongoDB权限机制
创建账号:
db.createUser({
"user": 你的账号,
"pwd": 你的密码,
"roles": [{
role: 角色,
db: 所属数据库
}]
})
角色
-- 角色种类
超级用户角色:root
数据库用户角色:read、readWrite
数据库管理角色:dbAdmin、userAdmin
集群管理角色:clusterAdmin、clusterManager、clusterMonitor、hostManager
备份恢复角色:backup、restore
所有数据库角色:readAnyDatabase、readWriteAnyDatabase、userAdminAnyDatabase、dbAdminAnyDatabase
-- 角色说明
root:只在admin数据库中可用。超级账号,超级权限
read:允许用户读取指定数据库
readWrite:允许用户读写指定数据库
开启验证模式
开启验证模式概念:指用户需要输入账号密码才能登录使用
操作步骤:
1. 添加超级管理员
2. 退出卸载服务
3. 重新安装需要输入账号密码的服务
4. 启动服务 -> 登录测试
-
步骤1:添加超级管理员
使用DOS命令行 use admin db.createUser({ "user": "admin", "pwd": "admin888", "roles": [{ role: "root", db: "admin" }] })
-
步骤2:退出卸载服务
使用管理员身份打开DOS窗口,进入MongoDB的bin目录下,执行 mongod --remove
-
步骤3:重新安装徐奥输入账号密码的服务
使用管理员身份打开DOS窗口,进入MongoDB的bin目录下,执行 mongod --install --dbpath db数据路径 --logpath 日志路径 --auth
-
步骤4:启动服务 -> 登录测试
启动服务:net start mongodb 进入:mongo
通过超级管理员账号登录
用户是给数据库加的
方法1:mongo 服务器IP地址:端口号/数据库 -u 用户名 -p 密码
方法2:a-先登录,b-选择数据库,c-输入db.auth(用户名, 密码)
MongoDB备份还原
备份数据库mongodump
-
语法
导出数据语法:mongodump -h -port -u -p -d -o 导出语法说明: -h host 服务器IP地址(一般不写,默认本机) -port 端口(一般不写,默认27017) -u user 账号 -p pwd 密码 -d database 数据库(数据库不写则导出全部) -o open 备份到指定目录
练习:备份所有数据:
mongodump -u admin -p admin888 -o C:\MongoDB\Server\bin\bak
练习:备份指定数据:
mongodump -u shop1 -p admin888 -d shop -o C:\MongoDB\Server\bin\bak2
还原数据库mongorestore
-
语法:
还原数据语法:mongorestore -h -port -u -p -d --drop 备份数据目录 还原数据说明: --drop 先删除数据库再导入,不写则覆盖 其他参数同备份
练习:还原所有数据:
mongorestore -u admin -p admin888 --drop C:\MongoDB\Server\bin\bak
练习:还原指定数据:
mongorestore -u shop1 -p admin888 --drop C:\MongoDB\Server\bin\bak2
接口数据:
{
meta: {
msg: 提示信息,
status: 状态码(200/201/301/400/401/403/404/500)
},
data:数据
}