一:MongoDB基本概念详解
MongoDB中的记录是一个文档,它是由字段和值对组成的数据结构。MongoDB文档类似于JSON对象。字段的值可以包括其他文档,数组和文档数组。MongoDB数据模型和你的对象在内存中的表现形式一样,一目了然的对象模型。
![](https://i-blog.csdnimg.cn/blog_migrate/40a3e1ca664dca27b9343cc782a47e98.png)
关系型数据库和文档型数据库主要概念对应
![](https://i-blog.csdnimg.cn/blog_migrate/6c871d19f8bf00d0588b28d119bcc6af.png)
二:MongoDB的基本操作
2.1:添加数据
1:单个添加:
db
.
emp
.
insertOne
(
{
name
:
"zhangsan"
,
age
:
20
,
sex
:
"m"
} );
2:多个添加
db
.
inventory
.
insertMany
([
{
item
:
"journal"
,
qty
:
25
,
status
:
"A"
,
size
:
{
h
:
14
,
w
:
21
,
uom
:
"cm"
},
tags
:
[
"blank"
,
"red"
] },
{
item
:
"notebook"
,
qty
:
50
,
status
:
"A"
,
size
:
{
h
:
8.5
,
w
:
11
,
uom
:
"in"
},
tags
:
[
"red"
,
"blank"
] },
{
item
:
"paper"
,
qty
:
10
,
status
:
"D"
,
size
:
{
h
:
8.5
,
w
:
11
,
uom
:
"in"
},
tags
:
[
"red"
,
"blank"
,
"plain"
] },
{
item
:
"planner"
,
qty
:
0
,
status
:
"D"
,
size
:
{
h
:
22.85
,
w
:
30
,
uom
:
"cm"
},
tags
:
[
"blank"
,
"red"
] },
{
item
:
"postcard"
,
qty
:
45
,
status
:
"A"
,
size
:
{
h
:
10
,
w
:
15.25
,
uom
:
"cm"
},
tags
:
[
"blue"
] }
],
{
writeConcern
:
doc
,//安全级别,可选字段
ordered
:
true
/
false
}
);
3:注意点:
1)writeConcern:决定一个写操作落到多少个节点上才算成功。 writeConcern的取值包括
0: 发起写操作,不关心是否成功
1- 集群中最大数据节点数: 写操作需要被复制到指定节点数才算成功
majority: 写操作需要被复制到大多数节点上才算成功,发起写操作的程序将阻塞到写操作到达指定的节点数为止
2)ordered:
顺序写入时,一旦遇到错误,便会退出,剩余的文档无论正确与否,都不会写入乱序写入,则只要文档可以正确写入就会正确写入,不管前面的文档是否是错误的文档。
2.2:文档的查询
1:整个文档的查询
db.inventory.find({}) //查询所有的文档
db.inventory.find({}).pretty() //返回格式化后的文档
2:条件查询
1)精准等值查询
db.inventory.find( { status: "D" } );
db.inventory.find( { qty: 0 } );
2)多条件查询
db.inventory.find( { qty: 0, status: "D" } );
3)嵌套对象精准查询
db.inventory.find( { "size.uom": "in" } );
4)返回指定字段
db.inventory.find( { },
{ item: 1, status: 1 }
);
默认会返回_id 字段, 同样可以通过指定 _id:0 ,不返回_id 字段
5)条件查询 and
db.inventory.find({$and:[{"qty":"0"},{"status":"A"}]}).pretty();
6)条件查询 or
db.inventory.find({$or:[{"qty":"0"},{"status":"A"}]}).pretty();
2.3:逻辑操作符匹配
1:$not : 匹配筛选条件不成立的文档
用法:{ field: { $not : { operator‐expression} }}
如:db.members.find({points: { $not: { $lt: 100}}} );//查找积分不小于100的
2:
$and : 匹配多个筛选条件同时满足的文档
用法:
{
$and
:
[
condition expression1
,
condition expression2
..... ]}
如:
db
.
members
.
find
({
$and
:
[ {
nickName
:
{
$eq
:
"
曹操
"
}}, {
points
:
{
$gt
:
1000
}}]});
也可省略
$and,
db
.
members
.
find
({
nickName
:
{
$eq
:
"
曹操
"
},
points
:
{
$gt
:
1000
}});
如果作用于同一个字段,可以再次修改如下:
db
.
members
.
find
({
points
:
{
$gte
:
1000
,
$lte
:
2000
}});
3:
$or : 匹配至少一个筛选条件成立的文档
用法:
{
$or
:
{
condition1
,
condition2
,
condition3
,... }}
如:
db
.
members
.
find
(
{
$or
:
[
{
nickName
:
{
$eq
:
"
刘备
"
}},
{
points
:
{
$gt
:
1000
}}]}
);
注意:如果是等值查询的话,
$or于$in一致
4:
$nor : 匹配多个筛选条件全部不满足的文档
5:$exists:匹配包含查询字段的文档
用法:
{
field
:
{
$exists
:
<
boolean
>} }
2.4:文档的删除
db
.
collection
.
remove
(<
query
>,<
options
>) 默认情况下,会删除所有满足条件的文档, 可以设定参数 { justOne:true},只会删除满足添加的第一条文档
db
.
collection
.
drop
( {
writeConcern
:
<
doc
>})
这个指令不但删除集合内的所有文档,且删除集合的索引
2.5:文档的更新
db
.
collection
.
update
( <
query
>,<
update
>,<
options
>)
<query> 定义了更新时的筛选条件
<update> 文档提供了更新内容
<options> 声明了一些更新操作的参数
如:
db
.
doc
.
update
(
{
name
:
"zhangsan"
},
{
$set
:
{
flag
:
1
}},
{
multi
:
true
}
);
更新操作符:
$set 更新或新增字段
$unset删除字段
$rename 重命名字段
$inc 加减字段值
$mul 相乘字段值
$min 采用最小值
$max 次用最大值
三:MongoDB的聚合操作
3.1 聚合管道阶段
1)
$project 对输入文档进行再次投影
列如:db
.
userInfo
.
aggregate
({
$project
:
{
name
:
"$nickName"
}});
将集合中的 nickName 投影成name。
$project 也可以灵活控制输出文档的格式,也可以剔除不需要的字段
db
.
userInfo
.
aggregate
({
$project
:
{
name
:
"$nickName"
,
_id
:
0
,
age
:
1
}});
2)
$match 对输入文档进行筛选
列如:
db
.
userInfo
.
aggregate
({
$match
:
{
nickName
:
"lisi"
}});
3)$limit 筛选出管道内前 N 篇文档
db
.
userInfo
.
aggregate
({
$limit
:
1
});
4)$skip 跳过管道内前N篇文档
db
.
userInfo
.
aggregate
({
$skip
:
1
});
5)
$unwind 展开输入文档中的数组字段
db
.
userInfo
.
aggregate
(
{
$unwind
:
{
path
:
"$tags"
}}
);
includeArrayIndex: 加上数组元素的索引值, 赋值给后面指定的字段
db
.
userInfo
.
aggregate
(
{
$unwind
:
{
path
:
"$tags"
,
includeArrayIndex
:
"arrIndex"
}}
);
preserveNullAndEmptyArrays:true。展开时保留空数组,或者不存在数组字段的文档
db
.
userInfo
.
aggregate
(
{
$unwind
:
{
path
:
"$tags"
,
includeArrayIndex
:
"arrIndex"
,
preserveNullAndEmptyArrays
:
true
}
}
);
6)$sort 对文档进行排序: 1 正序, -1 倒序
db
.
userInfo
.
aggregate
({
$sort
:
{
age
:‐
1
}});
7)$lookup 对输入文档进行查询操作
$lookup
:
{
from
:
需要关联的文档
,
localField
:
本地字段,
foreignField
:
外部文档关联字段,
as
作为新的字段,添加到文档中
}
![](https://i-blog.csdnimg.cn/blog_migrate/30782ec71977116e007c5d86ad73ee93.png)
8)$group 对输入文档进行分组
$group
:
{
_id
:
对哪个字段进行分组,
field1
:
{
accumulator1
:
expression1
}
}
对于group,聚合操作主要有以下几种
$addToSet :将分组中的元素添加到一个数组中,并且自动去重
$avg 返回分组中的平均值, 非数值直接忽略
$first 返回分组中的第一个元素
$last 返回分组中的最后一个元素
$max 返回分组中的最大元素
$min 回分组中的最小元素
$push 创建新的数组,将值添加进去
$sum 求分组数值元素和
注意:group 阶段有 100m内存的使用限制, 默认情况下,如果超过这个限制会直接返回 error,可以通过设置 allowDiskUse 为 true 来避免异常, allowDiskUse 为 true 将利用临时文件来辅助实现group操作。
9)$out 对管道中的文档输出
3.2 管道优化
1. 投影优化
聚合管道可以确定它是否仅需要文档中的字段的子集来获得结果。如果是这样,管道将只使用那些必需的 字段,减少通过管道的数据量。
2. 管道符号执行顺序优化
对于包含投影阶段($project或$unset或$addFields或$set)后跟$match阶段的聚合管道,MongoDB 将$match阶段中不需要在投影阶段计算的值的任何过滤器移动到投影前的新$match阶段。
3. $sort + $match
如果序列中带有$sort后跟$match,则$match会移动到$sort之前,以最大程度的减少要排序的对象的数量。
4. $project/ $unset + $skip序列优化
当有一个$project或$unset之后跟有$skip序列时,$skip 会移至$project之前。
5.$limit+ $limit合并
当$limit紧接着另一个时 $limit,两个阶段可以合并为一个阶段 $limit,其中限制量为两个初始限制量中的较小者。
6. skip+ $skip 合并
当$skip紧跟另一个$skip,这两个阶段可合并成一个单一的$skip,其中跳过量为总和的两个初始跳过量。
7. $match+ $match合并
当一个$match紧随另一个紧随其后时 $match,这两个阶段可以合并为一个单独 $match的条件 $and
四:索引
MongoDB的索引与MySql一致,都是采用B+tree的方式,大致结构如下图
![](https://i-blog.csdnimg.cn/blog_migrate/4ce3bbcf5ea128cd91eb47d568810c35.png)
创建索引
db.collection.createIndex(<keys>, <options>)
列如:
db
.
members
.
createIndex
({
name
:
1
}
,
{
name
:
"whatever u like."
});为索引取别名
删除索引
db
.
collection
.
dropIndex
()
索引的唯一性:
索引的unique属性使MongoDB拒绝索引字段的重复值:
db
.
members
.
createIndex
({
age
:
1
},{
unique
:
true
});
索引的生存时间:对日期字段,或者包含了日期元素的数组字段,可以使用设定了生存时间的索引,来自动删除字段值超过生存时间的文档。
db . members . createIndex ({ create_time : 1 },{ expireAfterSeconds : 30 });
db . members . createIndex ({ create_time : 1 },{ expireAfterSeconds : 30 });
注意:
复合键索引不具备生存时间的特性
索引的效果解析
COLLSCAN: 整个集合扫描
IXScan: 索引扫描
FETCH: 根据索引指向的文档的地址进行查询
SORT: 需要再内存中排序,效率不高
五:MongoDB高可用复制集架构
5.1 MongoDB复制集
MongoDB复制集的主要意义在于实现服务高可用,类似于Redis中的哨兵模式。
5.2 作用
1. 数据写入主节点(Primary)时将数据复制到另一个副本节(Secondary)点上
2. 主节点发生故障时自动选举出一个新的替代节点
3.数据分发:将数据从一个区域复制到另一个区域,减少另一个区域的读延迟
4.读写分离:不同类型的压力分别在不同的节点上执行
5.异地容灾:在数据中心故障时快速切换到异地
5.3 典型复制集结构
一个典型的复制集由三个或三个以上具有投票权的节点组成,其中一个主节点(Primary):接收写入操作,读操作和选举时投票,两个或多个从节点(Secondary):复制主节点上的新数 据和选举时投票
5.4 数据是如何复制的?
当一个修改操作,无论是插入,更新或删除,到达主节点时,它对数据的操作将被记录下来(经过一些必要的转换)。这些记录称为oplog,从节点通过从主节点上不断获取新进入主节 点oplog,并在自己的数据上回放,以此保持跟主节点的数据一致。
六:MongoDB集群分片机制原理
七:MongoDB应用与开发实战