一、业务应用场景
三高需求:
- 高并发读写需求
- 海量数据的高效率存储和访问的需求
- 对数据库的高扩展性和高可用性的需求
应用场景:
- 社交场景,使用MongoDB存储用户信息,以及用户发表的朋友圈信息,通过地理位置索引实现附近的人,地点等功能
- 游戏场景:方便查询、高效率存储和访问
- 物流场景:使用MongoDB存储订单信息
- 物联网场景:存入智能设备信息
- 视频直播:存储用户点赞、互动信息等
共同的特点:
- 数据量大
- 写入操作频繁(读写都很频繁)
- 价值低的数据,对事务的要求不高
什么时候选择mongoDB:
- 不需要事务及复杂的join支持
- 数据模型无法确定,想快速迭代开发
- 需要2000-3000以上的QPS
- 需要能够快速水平扩展
- 要求存储的数据不丢失
- 99.9999%可用
- 大量地理位置查询、文本查询
二、MongoDB简介
最像关系型数据库(MySQL)的非关系型数据库
特点:
高性能、高可用性、高扩展性、丰富的查询支持
三、单机部署
MongoDB的安装:
参考这篇文章:https://blog.csdn.net/weixin_70319460/article/details/126436904
基本命令
选择和创建数据库的语法格式:
选择和创建数据库的格式:
use 数据库名称
如果数据库不存在则自动创建,以下语句创建spitdb
数据库
use articledb
查看有权限查看的所有的数据库命令
show dbs
或show databases
注意:在MongoDB中,集合在内容插入后才会创建,就是说,创建集合(数据表)后要再插入一个文档(记录),集合才会真正的创建
查看当前正在使用的数据库命令
db
MongoDB中默认的数据库为test,如果没有选择数据库,集合将存放在test数据库中
另外:
数据库名可以满足以下条件的任意UTF-8字符串
- 不能是空字符串
- 不得含有'' (空格) . $ / \和\0 (空字符)
- 应全部小写
- 最多64个字节
有些数据库名是保留的,可以直接访问这些有特殊作用的数据库
- admin:从权限的角度看,这是root数据库,要是将一个用户添加到这个数据库,这个用户自动继承所有数据库的权限,一些特定的服务器端命令也只能从这个数据库运行,比如列出所有的数据库或者关闭服务器
- local:这个数据永远不会被复制,可以用来存储限于本地单台服务器的任意集合
- config:当Mongo用于分片设置时,config数据库在内部使用,用于保存分片的相关信息
数据库的删除:
dp.dropDatabase()
提示:用来删除已经持久化的数据库
集合操作
集合就相当于关系数据库中的表
显示创建:
可以显示创建,也可以隐式的创建
基本语法格式:
db.createCollection(name)
参数说明:
- name:要创建的集合名称
例如:创建一个名为myCollection
的普通集合
db.createCollection("mycollection")
查看当前库中的表:show tables
或者show collections
命令
隐式创建:
向一个集合中插入另一个文档的时候,如果集合不存在,则会自动创建集合
详见 文档的插入章节
提示:通常我们使用隐式创建文档即可
集合的删除:
db.collection名称.drop()
文档的CRUD
文档(document)的数据结构和JSON基本一样
所有存储在集合中的数据都是BSON格式
文档的插入:
1.单个文档插入
使用insert()或save()方法向集合中插入文档,语法如下:
db.collection名称.insert(
<document or array of document>,
{
writeConcern:<document>,
ordered:<boolean>
}
)
参数:
document、writeConcern、ordered
insert可以直接插入json
2.批量插入
db.collection名称.insertMany(
[<document 1>,<document 2>,...],
{
writeConcern:<document>,
ordered:<boolean>
}
)
文档的基本查询:
1.查询所有
如果我们查询split集合的所有文档,我们输入以下命令
db.comment.find()
或者db.comment.find({})
这里你会发现每条文档有一个叫_id
的字段,这个相当于原来关系型数据库中的主键,没有指定该字段时,MongoDB会自动创建,其类型是ObejectID类型
如果我们在插入文档记录时指定该字段也可以,其类型可以是ObjectID类型,也可以是MongoDB支持的任意类型
如果想查询userid为1003的记录
db.comment.find({userid:'1003'})
可能会返回满足条件的很多条,如果只想获取第一条则
db.comment.findOne({userid:'1003'})
2.投影查询
如果查询结果返回部分字段,则需要使用投影查询(不显示所有字段,只显示指定字段)
db.comment.find({userid:"1003"},{userid:1,nickname:1,_id:0})
在批量插入由于数据较多容易失败,因此可以使用try-catch进行异常处理,测试的时候可以不处理(了解)
文档的更新:
db.collection.update(query, update, options)
1.覆盖的修改
如果修改_id为1的记录,点赞量为1001,输入以下语句:
db.comment.update({_id:"1"},{likenum:NumberInt(1001)})
执行后会发现这条记录的除了likenum字段,其他字段都不见了
2.局部修改
为了解决这个问题,我们需要使用修改器\(set来实现,命令如下:
我们想修改_id为2的记录,浏览量为889,输入以下语句:
`db.comment.update({_id,"2"},{\)set:{likenum:NumberInt(889)}})`
这样就OK了
3.批量的修改
更新所有用户为1003的用户昵称为喵喵队,默认是只修改第一条
db.comment.update({userid:"1003"},{$set:{nickname:"喵喵队"}},{multi:true})
4.列值增长的修改
如果我们想实现对某列值在原有值基础上进行增加或减少,可以使用$inc
运算符来实现
需求:对3号数据的点赞数,每次递增1
db.comment.update({_id:"3"},{$inc:{likenum:NumberInt(1)}})
文档的删除
删除文档的语法结构:
db.集合名词.remove(条件)
以下语句可以将数据全部删除,请慎用
db.comment.remove({})
如果删除_id=1的记录,输入以下语句
db.comment.remove({_id:"1"})
文档的分页查询
1.统计查询
统计查询使用count()方法,语法如下
db.collection.count(query, options)
参数:query是查询选择条件、options可选,是用于修改计数的额外选项
实例:
- 统计所有记录数
统计comment集合的所有的记录数:
db.comment.count()
- 按条件统计记录数
统计userid为1003的记录条数
db.comment.count({userid:"1003"})
提示:
默认情况下count()方法返回符合条件的全部纪录条数
2.分页列表查询
可以使用limit()方法来读取指定数量的数据,使用skip()方法来跳过指定数量的数据
基本语法如下所示:
db.collection_name.find().limit(NUMBER).skip(NUMBER)
如果想要返回指定条数的记录,可以在find方法后调用limit来返回结果(TopN),默认值20,例如:
db.comment.find().limit(3)
skip方法同样接收一个数字参数作为跳过的记录条数(前N个不要),默认值是0
db.comment.find().skip(3)
分页查询:
# 第一页
db.comment.find().skip(0).limit(2)
# 第二页
db.comment.find().skip(2).limit(2)
# 第三页
db.comment.find().skip(4).limit(2)
3.排序查询
sort()方法对数据进行排序,sort()方法可以通过参数指定排序的字段,并使用1和-1来指定排序的方式,其中1为升序排列,而-1是用于降序排列
语法如下所示:
db.collection_name.find().sort({key:1})
或者
db.集合名称.find().sort(排序方式)
例如:
对userid降序排列,并对访问量进行升序排列
db.comment.find().sort({userid:-1,likenum:1})
文档更多的查询
1.正则的复杂条件查询
MongoDB的模糊查询是正则表达式方式实现的,格式为
db.collection.find({field:/正则表达式/})
或
db.集合.find({字段:/正则表达式/})
提示:正则表达式是js语法,直接量的写法
2.比较查询
<,<=,>,>= 这个操作符也是很常用的,格式如下:
db.集合名称.find({"field":{ $gt: value }}) // 大于: field> value
db.集合名称.find({"field":{ $lt: value }}) // 小于: field< value
db.集合名称.find({"field":{ $gte: value }}) // 大于等于: field >= value
db.集合名称.find({"field":{ $lte: value }}) // 小于等于: field <= value
db.集合名称.find({"field":{ $ne: value }}) // 不等于: field != value
实例:查询评论点赞数量大于700的记录
db.comment.find({likenum:{$gt:NumberInt(700)}})
3.包含查询
包含使用\(in操作符
示例:查询评论的集合中userid字段包含1003或1004的文档
`db.comment.find({userid:{\)in:["1003","1004"]}})不包含使用$nin操作符 示例:查询评论的集合中userid字段不包含1003或1004的文档
db.comment.find({userid:{$nin:["1003","1004"]}})`
4.条件连接查询
如果我们需要查询两个以上条件,需要使用\(and操作符进行关联(相当于SQL的and)
`\)and:[{},{},{}]示例:查询评论集合中likenum大于等于700 且小于2000的文档
db.comment.find(\(and:[{likenum:{¥gte:NumberInt(700)}},{likenum:{\)lt:NumberInt(2000)}}])如果两个以上条件是或者的关系,我们使用操作符进行关联,与前面and的使用方式相同
$or:[{},{},{}]`
索引-Index
mySQL的索引使用的是B+树,MongoDB的索引使用的是B树
索引为的类型
1.单字段索引
MongoDB支持在单个字段上创建用户定义的升序/降序索引,称为单字段索引,对于单个字段索引和排序操作,索引键的排序顺序(升序或降序)并不重要,因为MongoDB可以在任何方向上遍历索引
2.复合索引
复合索引中列出的字段顺序具有重要意义,比如复合索引由{userid:1,score:-1}
组成,则索引首先按userid正序排序,然后在每个userid的值内,再按照score倒序排序
3.其他索引
地理空间索引、文本索引、哈希索引
索引的管理操作
在集合上创建索引
db.collection.createIndex(keys, options)
建立单个索引
db.comment.createIndex({userid:1})
建立复合索引
db.comment.createIndex({userid:1,nickname:-1})
索引的移除
指定索引的移除
db.collection.dropIndex(index)
所有索引的移除
db.collection.dropIndexes()
索引的使用
执行计划
分析查询性能,通常使用执行计划查看查询的情况比如查询耗费时间,是否基于索引查询等
通常我们想知道,建立的索引是否有效,效果如何都需要通过执行计划查看
db.collection.find(query,options).explain(options)
涵盖的查询
当查询条件和查询的投影仅包含索引字段时,MongoDB直接从索引返回结果,而不扫描任何文档或将文档带入内存,这些覆盖的查询可以非常有效
副本集的创建
添加副本从节点
rs.add(host, arbiterOnly)
副本集的数据读写操作
设置奴隶节点,允许从成员上运行读的操作
语法:
rs.slaveOk()
或者rs.slaveOk(true)
想取消的话把true改成false
仲裁者节点,不存放任何业务数据,可以登录查看
主节点的选举原则
MongoDB在副本集中,会自动进行主节点的选举,主节点选举的触发条件
- 主节点故障
- 主节点网路不可达(默认心跳信息是10s)
- 人工干预(rs.stepDown(600))
一旦触发选举,就要根据一定的规则来选取主节点
选举规则是根据票数来决定谁获胜
- 票数最高,且获得了"大多数"成员的投票支持的节点获胜
“大多数”的定义为,假设复制集内投票成员数量为N,则大多数为N/2+1,例如:3个投票成员,则大多数的值是2,当复制集内存活成员数量不足大多数时,整个复制集将无法选举出Primary,复制集将无法提供写服务,处于只读状态
- 若票数相同,且都获得了大多数成员的投票支持,根据新的节点获胜
数据的新旧是通过操作日志oplog来对比的
分片集群
分片是一种跨多台机器分布数据的方法,MongoDB使用分片来支持具有非常大的数据集和高吞吐量操作的部署
分片集群包含:
- 分片(存储):每个分片包含分片数据的子集,每个分片都可以部署为副本集
- mongos(路由):mongos充当查询路由器,在客户端应用程序和分片集群之间提供接口
- config servers ("调度"的配置):配置服务器存储群集的元数据和配置设置,从MongoDB3.4开始,必须将配置服务器部署为副本集(CSRS)