1. 聚合(Aggregation Framework)
聚合是 MongoDB
中最强大的分析与数据处理工具,相当于 SQL
中的 GROUP BY
、JOIN
、WHERE
、ORDER BY
等组合。
1.1 聚合管道的基本原理
MongoDB
的聚合是一个数据流管道:
1 | 输入文档 → $match → $group → $sort → $project → 输出结果 |
每个阶段都会对数据进行筛选、计算、排序或重塑。
1.2 常用聚合操作
1) $match 过滤数据
1 | db.orders.aggregate([ |
2) $group 分组统计
它会按照 _id
字段的值来分组,然后对每组数据做聚合计算
1 | db.orders.aggregate([ |
相当于:
- 按
customerId
字段的值来分组 - 建一个字段
totalSpent
, 对每个分组内所有文档的amount
字段做求和
常用聚合运算符
运算符 | 作用 |
---|---|
$sum | 求和 |
$avg | 平均值 |
$min | 最小值 |
$max | 最大值 |
$firs | 每组第一条记录 |
$last | 每组最后一条记录 |
$push | 把每个值放进数组 |
$addToSet | 去重后放进数组 |
3) $project 重塑字段
1 | db.orders.aggregate([ |
相当于:
不要
_id
(MongoDB
默认会带上_id
,所以这里显式关掉)。保留
orderId
。新增
amountUSD
字段,它的值来自amount
字段。
4) $sort 排序
1 | db.orders.aggregate([ |
1 表示升序(从小到大)
-1 表示降序(从大到小)
1
2
3{ $sort: { amount: -1, orderId: 1 } }
表示先按 `amount` 降序,金额相同的再按 `orderId` 升序。
5) $lookup 关联集合(类似 SQL JOIN)
1 | db.orders.aggregate([ |
对
orders
集合中的每条文档,取出它的customerId
。在
customers
集合中查找_id
等于customerId
的文档。把匹配到的所有
customers
文档放进当前订单文档的customerInfo
数组字段里。as:新建一个字段名
,关联匹配到的结果都会放在这个字段下,是一个数组,即使匹配只有一个也会是数组。
1.3 聚合示例:统计用户总消费金额并排序
1 | db.orders.aggregate([ |
2. 副本集(Replica Set)
2.1 副本集的作用
高可用:主节点宕机,自动选举新的主节点。
读写分离:读操作可以分担到从节点。
数据冗余:多节点保存相同数据,防止单点故障。
2.2 副本集架构图
1 | +----------------+ |
2.3 启动副本集
假设我们有三台服务器:
1 | mongod --replSet rs0 --port 27017 --dbpath /data/node1 --bind_ip localhost |
2.4 初始化副本集
1 | rs.initiate({ |
3. 分片(Sharding)
3.1 分片的作用
水平扩展(
Scale-out
):将数据分布到多台服务器,打破单机性能瓶颈。海量数据存储:支持
TB
甚至PB
级数据。自动路由:客户端不需要关心数据在哪个分片。
3.2 分片架构图
1 | +---------+ +------------+ |
3.3 启动分片集群
1 | # 启动配置服务器 |
3.4 添加分片
1 | sh.addShard("localhost:27018") |
3.5 启用集合分片
1 | sh.enableSharding("mydb") |
4. 高级最佳实践
聚合优化
$match
尽量放在前面,减少后续数据处理量。使用
$project
只保留必要字段。
副本集优化
主节点存储用
SSD
,保证写入性能。从节点可以用于只读分析,减轻主节点压力。
分片优化
选择高基数字段作为分片键(如
userId
)。避免使用时间戳作为唯一分片键(会导致热点写入)。
监控与运维
使用
mongostat
、mongotop
实时监控。部署
MongoDB Atlas
或Prometheus + Grafana
进行可视化监控。
5. 总结
*聚合 让
MongoDB
拥有SQL
级别的数据分析能力。*副本集 提供高可用和读写分离。
*分片 让
MongoDB
可以支撑超大规模数据。
如果你是中小型应用,可以只部署 副本集,确保高可用。
如果你是大型应用,需要水平扩展,那就必须上 分片 + 副本集 架构。