MongoDB基础
参考资料
- 在线练习地址:https://mongodb.net.cn/manual/tutorial/getting-started/
- https://zhuanlan.zhihu.com/p/497736109
- https://mongodb.net.cn/manual/crud/#create-operations
安装与配置
安装
-
下载地址:https://www.mongodb.com/zh-cn/products/updates/version-release
-
https://www.zhihu.com/question/548433431/answer/2672554145
在 mongodb4.5 的版本中逐渐改用 mongosh 来连接数据库,在 6 版本中已经完全弃用 mongo 这个 shell 命令
mongosh 是功能更强大的下一代 MongoDB Shell,提供了语法高亮、智能提示等增强功能
配置
配置环境变量
双击 Path,新建一个并输入自己 MongoDB 的安装位置
例如:D:\MongoDB\Server\6.0\bin
运行 MongoDB 服务
-
创建数据库文件的存放位置
为了防止启动 MongoDB 服务失败,启动之前需要必须创建数据库文件的存放文件夹
在路径D:\MongoDB\Server\6.0\data下,创建一个 db 文件夹 -
启动 MongoDB 服务
1、打开 cmd
2、切换到 MongoDB 的 db 文件路径下
3、输入命令mongod --dbpath D:\MongoDB\Server\6.0\data\db,回车
4、仔细看一下是否有"port":27017的字样,端口号一般为 27017
5、然后在浏览器中输入地址和端口号为:http://localhost:27017
会出现一句话: It looks like you are trying to access MongoDB over HTTP on the native driver port. -
结束此次 MongoDB 服务
连续按两次
Ctrl C -
配置本地 Windows MongoDB 服务(可选)
此步骤是为了 方便启动和关闭 MongoDB 服务
-
先在
D:\MongoDB\Server\6.0\data文件下创建新文件夹 log(用来存放日志文件) -
新建配置文件 mongo.config
切换到路径
D:\MongoDB\Server\6.0\bin下,新建一个 mongo.config 文本文件,输入:1 2dbpath=D:\Mongodb\Server\6.0\data\db logpath=D:\Mongodb\Server\6.0\data\log\mongo.log -
用 管理员身份 运行 cmd,切换到路径
D:\MongoDB\Server\6.0\bin下,执行1mongod -dbpath "D:\Mongodb\Server\6.0\data\db" -logpath "D:\Mongodb\Server\6.0\data\log\mongo.log" -install -serviceName "MongoDB" -
在这之后,可以通过 cmd 打开服务
启动 MongoDB
net start MongoDB
关闭 MongoDBnet stop MongoDB
查看正在运作的 MongoDB 服务services.msc
-
快速入门
| SQL | MongoDB | 解释 |
|---|---|---|
| database | database | 数据库 |
| table | collection | 表/集合 |
| row | document | 行/文档 |
| column | field | 字段/域 |
| index | index | 索引 |
| table joins | \ | 表连接,MongDB 不支持 |
| primary key | primary key | 主键 |
| Mysqld | mongod | 服务端 |
| mysql | mongo | 客户端 |
MongoDB 的 数据库 中有很多 集合
集合中每行称为 文档
每列称为 域
数据库(database)
可以建立多个数据库
默认数据库为 db,该数据库存储在 data 目录中
show dbs 显示所有数据的列表
db 显示当前数据库对象或集合
use mydatabase 连接到一个指定的数据库 mydatabase
数据库命名注意:
1、不能是空字符串
2、不能含有 空格 $ / \ \0 和 .
5、不要命名为 admin、local、config
3、全部小写
4、最多 64 字节
集合(collection)
集合又叫做文档组
存在于数据库中,没有固定的结构,所以可以插入 不同格式和类型 的数据
但是通常会有 一定的关联性
集合命名注意:
1、不能是空字符串
2、不能含有 $ \0
3、不要以 system. 开头
-
capped collections
即固定大小的 collection,意味着存储空间提前分配
拥有很高的性能、队列过期的特性
适合记录日志创建一个名为 mycoll 的 capped collection
指定大小为 100000 字节1db.createCollection("mycoll", {capped:true, size:100000})
文档(document)
键值对
文档之间不需要设置相同的字段
即使相同的字段也不需要设置相同的数据类型
注意:
1、键值对 有序
2、区分类型和大小写
3、不能有重复的键
4、键一般为字符串,少数例外
5、值可以是其他数据类型
6、键不能含有 $ \0 和 .,因为 \0 表示字符串的结尾
7、尽量不使用 _ 开头的键名
元数据
使用了系统的命名空间:dbname.system.*
命名 描述 dbname.system.namespaces 列出所有的名字空间 dbname.system.indexes 列出所有的索引 dbname.system.profile 列出该数据库的概要信息 dbname.system.users 列出所有的可以访问该数据库的用户 dbname.system.sources 列出服务器信息和状态
核心特性
无架构 No Schema
文档型数据库,文档组织结构是类 JSON 的 BSON
是二进制的存储格式(额外支持 Date 等数据类型)
这使得数据库中的对象的表现能力更强
字段管理灵活,便于增减字段,也就便于开发和快速迭代
高可用
对于单个 mongod 实例的崩溃的情况下,可以通过 checkpoint(持久化点)恢复到上一个 60 秒之前的数据
而最后一个 checkpoint 到重启期间的数据可以通过 oplog 恢复
-
怎么做到的高可用?
通过复制集群,本质是数据存储多份,保证一台机器宕机而数据不会丢失
一个副本集至少有 3 个节点,主节点>=1、从节点>=2、仲裁节点 0/1
主节点负责写操作,从节点进行数据同步,仲裁节点负责主节点选举在副本集的高可用场景下,主节点宕机后,系统是通过选举出新主节点来恢复服务的,数据由新主节点提供,这个过程是自动的,对应用透明
原主节点重启后会作为从节点,通过拉取新主节点的 oplog 来同步数据
可扩展性
支持水平扩展,不再担心分库分表的问题
分片集群架构
将存储进行分片,再通过一个 proxy 作为请求路由
一个重要的特性是 数据均衡,数据各个分片的分布均匀,负载均衡,最大化利用集群资源
| 部分 | 解释 |
|---|---|
| Configs | 配置,是 MongoDB 的副本集,存储元数据和配置 |
| Mongos | 路由服务,转发请求到分片,整合分片结果 |
| Mongod | 单个分片 |
-
数据均衡实现方式
在 MongoDB 分片集群中,数据被分割成多个 Chunk 作为管理和迁移的基本单位。每个 Chunk 默认大小为 64MB,并可在一定范围内配置(0~1024M)
当 Chunk 的大小因数据写入而超过设定阈值时,MongoDB 会自动将其分裂为两个较小的 Chunk。所有 Chunk 的元数据信息都存储在配置服务器 Configs 中
为了实现数据的均匀分布,MongoDB 的均衡器会持续监控各个分片上的 Chunk 数量。当分片间的 Chunk 数量差异达到迁移阈值时,均衡器会自动发起 Chunk 迁移,将 Chunk 从负载较高的分片移动到负载较低的分片
由于 Chunk 迁移会消耗较多的集群资源(如网络和磁盘 I/O),通常建议在业务低峰期进行,或者通过设置均衡窗口来严格控制迁移的执行时间 -
MongoDB 的分片机制的核心
首先需要为集合选择一个或多个字段作为 分片键 shardkey
根据 shardkey 的值,通过特定的 分片策略 将其映射到逻辑值域空间- 范围分片:f(x) = x。分片键值相近的文档很可能存储在同一个 Chunk 中,适合范围查询
- 哈希分片:f(x) = hash(x)。分片键值会被计算成一个哈希值,尽可能地将数据随机、均匀地分布 across 所有分片,有利于数据写入的均匀分布
上述的值域空间被划分为多个连续的区间,每个区间就是一个 Chunk。Chunk 的元数据信息(如区间范围、所在分片)被记录在配置服务器中
当进行数据操作时,路由节点(mongos)会根据分片键和分片策略计算出数据所属的 Chunk,再通过查询配置服务器,最终将请求路由到正确的分片上
数据压缩
MongoDB 会把客户数据先压缩再写入磁盘,节省存储空间
进阶知识
存储引擎
默认存储引擎 Wired Tiger,对应的存储结构是 B+ 树
B+ 树的特点是 中间节点只有索引,数据都存在叶子节点
MongoDB 的 B+ 树叶子节点的基本单元是 Page
每个 Page 上面有三个 list:
1、WT_ROW 磁盘加载进来的数据
2、WT_UPDATE 加载之后到下一个 checkpoint 之间被修改的数据
3、WT_INSERT 加载之后到下一个 checkpoint 之间新增的数据
内存 cache
MongoDB 的读写性能会随着数据量达到某个点出现断崖式跌落,而后趋于稳定
根本原因是内存的大小和数据量的关系
工作集(Working Set) 大小超过了物理内存容量,导致大量缺页中断(Page Fault),迫使系统在内存和磁盘间频繁交换数据,使得性能降低
checkpoint
将数据持久化到磁盘
Chunk
chunk 是一组 Document 组成的逻辑数据单元
是 分片集群的基本单元,用来管理数据存储和路由信息
chunk 分裂条件:chunk 的容量达到阈值;数据的条数达到阈值
rebalance:自动数据均衡,通过将 chunk 从数据多的分片迁移到数据少的分片来实现数据均衡
由于被设计成会尽快完成数据迁移,所以过程非常消耗系统资源
一致性/高可用
CAP 理论
一个分布式系统最多只能同时满足一致性、可用性、分区容错性这三项中的两项
MongoDB 遵循 BASE 理论(基本可用、软状态、最终一致性)
在副本集的 主从同步 存在延迟的时间窗口内,MongoDB 提供的是最终一致性(BASE),但在 写入被确认并复制 到大多数节点后,它能在这些节点上提供 强一致性
选举算法,基于 Raft 协议改进
三种状态:
1、leader,主节点,负责写操作
2、candidate,候选者,主节点挂掉后参与竞选
3、follower,从节点
-
完整的选举过程
多个 follower 节点未收到 leader 的心跳,便将自己改变成 candidate 状态,向其他节点发起投票请求
等待其他节点的投票返回,期间也可以给收到的请求投票
某个 candidate 收到 过半的赞成票 之后就把自己转换成 leader 状态,并发送心跳宣布继位
其他的 candidate 就退回到 follower 状态 -
存在的逻辑问题
follower 转换成 candidate 是随机并行的,不能保证选出的主节点是最优的
故 MongoDB 新增了 catchup 的操作,继位之前进行数据同步操作,保证最新的数据 -
主从同步
保证数据的一致性和可靠性
主节点接收客户端请求,更新操作写到 oplog,从节点再从同步源拉取 oplog 实现数据同步
常用语句
增删语句
-
创建数据库
1use mydatabase若 mydatabase 数据库存在的话,则切换过去
-
查看所有数据库
1show dbs会发现上面新建的 mydatabase 数据库显示不出来
因为是空的,需要先添加一些数据 -
添加数据
1db.mydatabase.insert({"game":"popkart"})再这之后查看数据库就可以看见 mydatabase 这个数据库了
注意
默认的数据库是 test
如果没有创建,集合将被存放在 test 数据库中 -
查看当前数据库名
1db -
删除数据库
1db.dropDatabase() -
删除集合
1db.collection.drop() -
插入文档
数据结构和 JSON 基本一样
1 2 3 4 5 6 7 8 9 10db.col.insert( { title: 'MongoDB 教程', description: 'MongoDB 是一个 Nosql 数据库', by: 'w3cschool', url: 'http://www.w3cschool.cn', tags: ['mongodb', 'database', 'NoSQL'], likes: 100 } )上述 col 是集合名
也可以先将数据定义为一个变量,再进行插入操作:1 2 3 4 5 6 7 8 9 10 11 12 13 14 15document=( { title: 'MongoDB 教程', description: 'MongoDB 是一个 Nosql 数据库', by: 'w3cschool', url: 'http://www.w3cschool.cn', tags: ['mongodb', 'database', 'NoSQL'], likes: 100 } ); db.col.insert(document) -- 或者 db.col.save(document) -- 区别是 save 可以指定 _id 字段 -
查看已插入文档
1 2 3db.col.find() -- 或者 db.col.find().pretty() -
更新已存在的文档
1 2 3 4 5 6db.col.update( {'year':'2019'}, {$set:{'year':'2020'}}, {multi:false} ) -- 其中的 multi 参数若为 true,则会修改多条相同的文档 -
删除文档
推荐删除之前使用
db.col.find()查看一下数据1 2 3 4 5db.col.remove( {"year":"2019"}, {justone:1} ) -- 其中的参数 justone 若为 1,表示只删除第一条找到的数据1 2-- 删除所有数据 db.col.remove({})
查询语句
-
数据展示
1db.COLLECTION_NAME.find().pretty() -
AND 条件
用 逗号隔开 即可
1 2 3 4 5 6db.col.find( { key1:value1, key2:value2 } ).pretty()筛选出 key1 的值为 value1 且 key2 的值为 value2 的数据
-
OR 条件
使用关键字
$or1 2 3 4 5 6 7 8db.col.find( { $or:[ {key1:value1}, {key2:value2} ] } ).pretty()筛选出 key1 的值为 value1 或者 key2 的值为 value2 的数据
-
AND 和 OR 联合使用
1 2 3 4 5 6 7 8 9db.col.find( { key1:value1, $or:[ {key21:value21}, {key22:value22} ] } ).pretty()筛选出 key1 的值为 value1 且 (key21 的值为 value21 或者 key22 的值为 value22) 的数据
-
大小比较
操作 关键字 MongoDB MySQL 等于 db.col.find({"cnt": 10}).pretty()where cnt = 10小于 $ltdb.col.find({"cnt": {$lt: 10}}).pretty()where cnt < 10小于等于 $ltedb.col.find({"cnt": {$lte: 10}}).pretty()where cnt <= 10大于 $gtdb.col.find({"cnt": {$gt: 10}}).pretty()where cnt > 10大于等于 $gtedb.col.find({"cnt": {$gte: 10}}).pretty()where cnt >= 10不等于 $nedb.col.find({"cnt": {$ne: 10}}).pretty()where cnt != 10除上述操作外,还可以联合使用 < 和 >
1 2 3 4 5db.col.find( { key: {$lt: 20, $gt: 10} } )筛选出 10 < key < 20 的数据
-
覆盖查询(Covering Query)
指的是查询操作能够完全通过索引来完成
不需要回表(即不需要访问实际的数据文档)来获取数据
提高查询效率和性能例如,如果你有一个索引包含了字段 A 和 B,而此时你的查询条件只涉及 A 和 B,那么这个查询就可以是覆盖查询
1 2 3 4 5-- 假设在 {name: 1, age: 1} 上创建了复合索引 db.users.find( {name: "Alice"}, {_id: 0, name: 1, age: 1} -- 只返回索引中包含的字段,且排除_id )-
速度快
因为索引通常存储在 RAM 中,而 RAM 的访问速度远快于磁盘
所以通过索引获取数据比扫描整个文档集要快得多 -
减少 I/O 操作
由于不需要回表,减少了对磁盘的读取操作,提高查询性能
-
减少数据传输
不需要从磁盘读取整个文档,减少了数据传输量
-
-
查询优化
-
查询分析
explain() 用来分析一条语句的索引使用情况、影响行数、执行时间等
可以检查自己的语句是否合理,建立的索引是否有效,以及可以据此进行优化1 2 3 4 5 6db.users.find( { name: "Alice", age: {$gt: 20} } ).explain("executionStats") -
hint()
强制 MongoDB 使用开发者所认为的最优的索引字段来执行查询
可以测试不同的索引对查询性能的影响1 2 3 4 5db.users.find( {name: "Alice"} ).hint({name: 1, age: -1}).toArray() -- 强制使用 {name: 1, age: -1} 索引来执行查询
-
$type 条件操作符
常见的 $type 对应的数字
| 类型 | 数字 | 备注 |
|---|---|---|
| Double | 1 | |
| String | 2 | |
| Object | 3 | |
| Array | 4 | |
| Binary data | 5 | |
| Undefined | 6 | 已废弃 |
| Object id | 7 | |
| Boolean | 8 | |
| Date | 9 | |
| Null | 10 | |
| Regular Expression | 11 | |
| JavaScript | 13 | |
| Symbol | 14 | |
| JavaScript (with scope) | 15 | |
| 32-bit integer | 16 | |
| Timestamp | 17 | |
| 64-bit integer | 18 | |
| Min key | 255 | Query with -1. |
| Max key | 127 |
假设要筛选出集合 “col” 中,title 为 String 类型的数据
|
|
limit 与 skip 方法
-
读取集合 col 中 num1 条数据记录
1db.col.find().limit(num1) -
跳过一定数量 num2 的数据再进行读取,可以配合 limit 使用
1 2db.col.find().limit(num1).skip(num2) -- skip 默认参数值为 0上述实例会显示从第 num2+1 条开始到第 num2+num1 条的数据
[num2+1, num2+num1]
排序、索引
-
排序
1db.col.find().sort({key: 1})上述语句查找出数据,并根据字段 key 进行 升序 排序
1 为升序排列,-1 为降序排列
索引是特殊的数据结构
对数据库表中一列或者多列的值进行排序,它存储在一个易于遍历读取的数据集合中
-
创建索引
索引通常可以提高查询的效率,否则每次筛选时都要扫描集合中的每个文件
-
key 是要创建的索引字段,1 指定为升序创建索引,同理 -1 为降序创建索引
1db.col.createIndex({key: 1}) -
设置多个字段来创建索引
1db.col.createIndex({key1: 1, key2: -1}) -
让创建索引的工作在后台执行
1 2-- createIndex() 方法还有很多可选参数 db.col.createIndex({key: 1}, {background: true})
-
-
高级索引
假设文档集合 users 中包含子文档 address 和数组 tags
1 2 3 4 5 6 7 8 9{ "address": { "city": "Los Angeles", "state": "California", "pincode": "123" }, "tags": ["music", "cricket", "blogs"], "name": "Tom Benzamin" }创建索引,这样可以通过 address 或者 tags 来检索用户
-
为子文档 address 创建索引
1 2 3 4 5 6 7db.users.createIndex( { "address.city": 1, "address.state": 1, "address.pincode": 1 } )通过子文档的字段检索数据
1 2 3 4 5 6 7db.users.find( { "address.city": "Los Angeles", "address.state": "California" } ) -- 注意按照索引创建的顺序进行筛选 -
为数组 tags 创建索引
1 2 3 4 5db.users.createIndex( { "tags": 1 } )通过数组的字段检索数据
1 2 3 4 5db.users.find( { tags: "cricket" } )
-
-
索引限制
-
创建的索引会占据一定的索引空间
如果很少对集合进行读取操作,建议不要使用索引
-
索引存储在内存(RAM)中,所以需要注意索引的大小
如果超过了内存,MongoDB 会删除一些索引,这将导致性能下降
-
可以用
.explain()来进行查询分析 -
限制
集合中索引不能超过 64 个
索引名的长度不能超过 125 个字符
一个复合索引最多有 31 个字段 -
无法使用索引的查询操作
正则表达式
非操作符,\$not等
算术运算符,\$mod等
\$where子句
-
-
全文检索
对每个词建立索引,指明该词在文章中的 位置和出现的次数
可以提高搜索效率-
启用全文索引
1 2 3 4 5 6db.adminCommand( { setParamter: true, textSearchEnable: true } )或者命令行执行
1mongod --setParamter textSearchEnable=true -
创建全文索引
1 2 3 4 5 6 7db.posts.createIndex( { post_text: "text" } ) -- 对 posts 集合中的 post_text 字段建立全文索引 -
使用全文索引
1 2 3 4 5db.posts.find( { $text: {$search: 。。。} } ) -
删除全文索引
1 2 3 4 5-- 先查找索引名 db.posts.getIndexes() -- 删除索引 db.posts.dropIndex("post_text_text")
-
-
正则表达式
使用单个字符串来描述、匹配一系列符合某个句法规则的字符串
使用$regex操作符来设置 匹配字符串 的正则表达式-
使用正则表达式
1 2 3 4 5 6 7 8db.col.find( { name: {$regex: "Tom", $options: "$i"} } ) -- 使用正则表达式查询 col 集合中,name 里面包含 Tom 的数据 -- $options: "$i" 设置查询不区分大小写等同于
1db.col.find({ name: /Tom/ })
-
聚合
可以用于统计平均值,求和等等,返回计算后的数据结果
|
|
等价于
|
|
-
常用的聚合表达式
表达式 描述 $sum计算总和 $avg计算平均值 $min获取集合中所有文档对应值的最小值 $max获取集合中所有文档对应值的最大值 $push在结果文档中,插入值到一个数组中 $addToSet同上,但是不创建副本 $first根据资源文档的排序获取第一个文档数据 $last根据资源文档的排序获取最后一个文档数据 -
管道的概念
在 linux 中,管道一般用于 将当前命令的输出结果作为下一个命令的参数。在 MongoDB 中是类似的
管道操作是可以重复的
表达式是无状态的,只能用于计算当前聚合管道的文档,不能用于处理其他文档表达式 描述 $project用于重命名、增加或删除域、创建计算结果或者嵌套文档 $match用于过滤数据 $limit限制管道返回的文档数 $skip跳过指定数量的文档 $unwind将文档中的某一个数组类型的字段拆分成多条,每条包含一个值 $group将集合中的文档分组 $sort将输入文档排序后输出 $geoNear输出接近某一地理位置的有序文档
其他
复制(副本集)
-
MongoDB 的复制
将数据同步在多个服务器的过程
复制提供了数据的冗余备份,提高数据的可用性,保证数据的安全性
当出现硬件故障或者服务中断的情况,可以恢复数据 -
原理
至少需要两个节点
1、主节点:一个,用于处理客户端请求
2、从节点:可以多个,用于复制主节点上的数据从节点会定期轮询主节点上记录的操作,然后对自己的数据副本执行
以保证了主从节点的数据一致 -
尝试做 MongoDB 主从实验
先关闭正在运行的 MongoDB 服务器
然后执行:1mongod --port 27017 --dbpath "D:\set up\mongodb\data" --replSet rs0上述语句会启动一个命为 rs0 的 MongoDB 实例,端口号为 27017
-
启动一个新的副本集
1rs.initiate() -
查看副本集的配置
1rs.conf() -
查看副本集状态
1rs.status() -
添加副本集的成员
1 2 3 4rs.add("mongo1.net : 27017") -- 假设之前已经启动了一个命为 mongo1.net,端口号为 27017 的服务 -- 上述语句可以将它添加到副本集中配置副本集的操作(如添加成员)需要在主节点上执行
在副本集初始化后,应该从主节点执行 rs.add() 命令,将其他服务器添加为新的从节点 -
判断当前服务是否为主节点
1db.isMaster()
副本集在主机宕机后,副本会接管主节点成为新的主节点
-
关系
文档之间的关系实际上是通过文档中的字段(通常是 ID 引用)来实现的
表示多个文档之间,在逻辑上的相互关系
例如:
1 : 1(1 对 1)
1 : N(1 对多)
N : 1(多对 1)
N : N(多对多)
-
嵌入式关系
正常查询即可
缺点是若数据量不断变大,会影响读写性能 -
引用式关系
users 集合和 address 集合通过引用 id 字段来建立关系
1 2 3 4 5 6 7 8 9 10 11 12-- 先查询 users 集合中符合条件的用户地址 id var result = db.users.findOne( {"name": "Tom"}, {"address_ids": 1} ) -- 再通过查询到的用户地址 id 获取用户的详细地址信息 var addresses = db.address.find( { "_id": {"$in": result["address_ids"]} } )
原子操作
在早期版本中,MongoDB 不支持事务,主要依靠原子操作来保证单个文档级别的完整性
但是从 MongoDB 4.2 版本开始,引入了多文档 ACID 事务支持,事务支持扩展到了分片集群。这意味着现在可以在 MongoDB 中执行跨多个文档、多个集合的真正事务操作,从而保证数据的完整性
原子操作
一件事要么完成要么不完成,所以文档要么保存成功要么没有保存
| 操作符 | 示例 | 说明 |
|---|---|---|
$set |
{ $set: { field: value } } |
指定一个键并更新其值,若键不存在则进行创建 |
$unset |
{ $unset: { field: 1 } } |
删除一个键 |
$inc |
{ $inc: { field: value } } |
对值为数值型的键进行增减 |
$push |
{ $push: { field: value } } |
将 value 追加到 field 中,要求 field 需要为数组类型的 若 field 不存在,则自动进行创建,且为数组类型的 |
$pushAll |
{ $pushAll : { field: value_array } } |
同 push,区别是可以一次追加多个值进去 |
$pull |
{ $pull: { field: value } } |
从 field 中删除一个等于 value 的值 |
$addToSet |
{ $addToSet: { field: value } } |
增加一个值到 field 中,当值不存在时才增加 |
$pop |
{ $pop: { field: 1 } } |
删除 field 的第一个或者最后一个元素 |
$rename |
{ $rename: { old_field_name: new_field_name } } |
修改字段名称 |
$bit |
{ $bit: { field: { and: 5 } } } |
GridFS
GridFS 会把大文件对象分割成多个小的 chunk(文件片段)
每个大小一般为 256 k,存储在 chunks 集合中
以及一个 files 文件来存放文件名、目录类型、自定义的属性
用于存储、恢复大小超过 16M 的文件
-
put 命令
1 2// 进入到 MongoDB 的 bin 目录中,使用 mongofiles.exe mongofiles.exe -d gridfs put song.mp3
固定集合
性能出色、大小固定
集合空间用完之后,会从头开始,并且覆盖原数据,可以理解为环形队列
可以用于存储日志信息,缓存一些少量的文档
-
创建固定集合
1 2 3 4 5 6db.createCollection( "cappedLogCollection", { capped : true, size : 10000, max : 1000 } ) -
判断集合 col 是否为固定集合
1db.col.isCapped() -
将已存在的集合 col 转换成固定集合
1 2 3 4 5 6db.runCommand( { "convertCapped" : "col", size : 10000 } ) -
调整数据返回顺序
固定集合返回的数据按照的是 插入数据的顺序
也可以使用 $natural 进行调整1db.cappedLogCollection.find().sort({$natural: -1})
分片
-
为什么使用分片
数据量大量增长,本地磁盘不足,不足以提供可接受的读写吞吐量
垂直扩展价格昂贵
请求量巨大时,会出现内存不足 -
三个重要组件
1、Shard:存储实际的数据块
2、Config Server:mongod 实例
3、Query Routers:前端路由 mongos -
分片步骤
启用分片是在 集合 级别进行的,需要先对数据库启用分片,再对指定集合启用分片并选择分片键
1 2sh.enableSharding("myDatabase") // 对数据库启用分片 sh.shardCollection("myDatabase.myCollection", {"shardKey": 1}) // 对集合进行分片1、启动 Shard Server
2、启动 Config Server
3、启动 Route Process
4、配置 Sharding
备份与恢复
-
数据备份
1mongodump -h dbhost -d dbname -o dbdirectory-h:MongoDB 所在服务器地址 -d:需要备份的实例 -o:备份数据存放位置
-
数据恢复
1mongorestore -h dbhost -d dbname --directoryperdb
注意以上命令需要切换到 mongodb\bin 目录下再执行
监控
目的是了解 MongoDB 的运行情况、查看 MongoDB 的性能
-
mongostat
内置的状态检测工具
间隔固定时间获取当前的运行状态
首先切换到 mongodb\bin 的目录下,再执行 mongostat -
mongotop
也是内置的工具
提供一个方法,可以 跟踪 一个 MongoDB 的实例,查看时间主要消耗在哪里
同理首先切换到 mongodb\bin 的目录下,再执行 mongotop
数据库引用
-
手动引用
-
DBRefs
一个文档从多个集合中引用文档
1 2 3 4 5{ $res: , $id: , $db: }$ref:集合名称$id:引用的 id$db:数据库名称,可选参数
ObjectId
ObjectId 是一个 12 字节的 BSON 类型数据
| xxxx | xxx | xx | xxx |
|---|---|---|---|
| 时间戳 | 机器识别码 | PID,进程 id | 随机数 |
每个集合都有唯一的 _id 值,确保里面的 文档能够被唯一标识
文档需要有一个 _id 键,其值可以是任意类型的,默认是 ObjectId
-
创建新的 ObjectId
1newObjectId = ObjectId() -
获取文档的时间戳
1newObjectId.getTimestamp() -
ObjectId 类型转字符串
1new ObjectId.str
Map Reduce
Map Reduce 是一种计算模式
将大规模工作分解(Map)执行,再将结果合并(Reduce)
可以用来构建大型复杂的聚合查询
|
|
包括 map 函数和 reduce 函数
map 函数生成键值对序列,把它作为参数传给 reduce 函数,注意必须调用 emit(key, value) 函数
reduce 函数做统计,将相同的键值整合起来
上述两个函数可以使用 js 实现,使用更加灵活且功能强大
虽然 Map-Reduce 功能强大且灵活,但需要指出的是,对于大多数聚合任务,聚合管道(Aggregation Pipeline) 是 MongoDB 官方更推荐、性能通常也更好的选择
Map-Reduce 使用 JavaScript,执行速度比用 C++实现的聚合管道要慢。可以将 Map-Reduce 视为一种更底层、更灵活但性能开销更大的工具
实操练习
CRUD
-
创建
db.collection.insert()
db.collection.insertOne()
db.collection.insertMany()1 2 3 4 5 6 7db.collection.insertOne( { name: 'sue', age: 26, status: 'working' } )1 2 3 4 5 6 7db.collection.insertMany([ { item: "journal", qty: 25, size: { h: 14, w: 21, uom: "cm" }, status: "A" }, { item: "notebook", qty: 50, size: { h: 8.5, w: 11, uom: "in" }, status: "A" }, { item: "paper", qty: 100, size: { h: 8.5, w: 11, uom: "in" }, status: "D" }, { item: "planner", qty: 75, size: { h: 22.85, w: 30, uom: "cm" }, status: "D" }, { item: "postcard", qty: 45, size: { h: 10, w: 15.25, uom: "cm" }, status: "A" } ]) -
查询
db.collection.find()
后面可以跟.limit(n)或者.pretty()等等1 2 3 4db.collection.find( { age: {$gt: 18} }, { name: 1, address: 1 } ) -
更新
db.collection.update()
db.collection.updateOne()
db.collection.updateMany()
db.collection.replaceOne()1 2 3 4db.collection.updateMany( { age: {$gt: 18} }, { $set: { status: 'working' } } ) -
删除
db.collection.deleteOne()
db.collection.deleteMany()1 2 3db.collection.deleteMany( { status: 'working' } )
实例
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|