MongoDB 的聚合框架(Aggregation Framework)提供了一种强大的方式来处理和分析数据。它允许你执行复杂的查询,包括分组、过滤、转换和计算等操作。聚合框架的核心是管道(Pipeline),这是一个由多个阶段(Stages)组成的序列,每个阶段都会对文档进行一系列的转换。
聚合框架的基本概念
- 管道:一个管道是由多个阶段组成的,每个阶段都对输入文档进行某种操作,并将结果传递给下一个阶段。
- 阶段:每个阶段都是一个特定的操作,如
$match
用于过滤文档,$group
用于分组和聚合,$sort
用于排序等。 - 表达式:在聚合管道中使用的各种表达式,如算术运算符、字符串函数、日期函数等。
常见的聚合阶段
以下是一些常用的聚合阶段及其功能:
- $match:过滤文档,类似于 SQL 中的
WHERE
子句。 - $project:选择或排除特定字段,可以重命名字段或创建新的计算字段。
- $group:根据指定的键对文档进行分组,并可以执行聚合操作,如计数、求和、平均值等。
- $sort:对文档进行排序。
- $limit:限制输出的文档数量。
- $skip:跳过一定数量的文档。
- $unwind:将数组字段拆分成多行。
- $lookup:执行左连接操作,类似于 SQL 中的
LEFT JOIN
。 - $addFields:向文档添加新的字段。
- $replaceRoot:替换根文档的内容。
- $count:返回匹配文档的数量。
- $facet:在一个阶段中执行多个聚合管道,并返回结果集。
- $bucket:根据指定的边界条件对数据进行分桶。
- $sample:随机采样文档。
示例
假设我们有一个 orders
集合,其中包含以下文档:
{ "_id" : 1, "item" : "apple", "price" : 100, "quantity" : 2, "date" : ISODate("2023-01-01T00:00:00Z") }
{ "_id" : 2, "item" : "banana", "price" : 50, "quantity" : 3, "date" : ISODate("2023-01-02T00:00:00Z") }
{ "_id" : 3, "item" : "orange", "price" : 75, "quantity" : 4, "date" : ISODate("2023-01-03T00:00:00Z") }
示例 1:按项目分组并计算总销售额
db.orders.aggregate([
{
$group: {
_id: "$item",
totalSales: { $sum: { $multiply: ["$price", "$quantity"] } }
}
},
{
$sort: { totalSales: -1 }
}
])
示例 2:筛选出 2023 年 1 月的订单,并按项目分组计算总数量
db.orders.aggregate([
{
$match: {
date: {
$gte: ISODate("2023-01-01T00:00:00Z"),
$lt: ISODate("2023-02-01T00:00:00Z")
}
}
},
{
$group: {
_id: "$item",
totalQuantity: { $sum: "$quantity" }
}
}
])
示例 3:使用 $lookup
进行左连接
假设我们还有一个 customers
集合,包含客户信息:
{ "_id" : 1, "name" : "Alice", "address" : "123 Main St" }
{ "_id" : 2, "name" : "Bob", "address" : "456 Elm St" }
并且 orders
集合中的每个订单都有一个 customerId
字段:
{ "_id" : 1, "item" : "apple", "price" : 100, "quantity" : 2, "customerId" : 1, "date" : ISODate("2023-01-01T00:00:00Z") }
{ "_id" : 2, "item" : "banana", "price" : 50, "quantity" : 3, "customerId" : 2, "date" : ISODate("2023-01-02T00:00:00Z") }
我们可以使用 $lookup
将 orders
和 customers
连接起来:
db.orders.aggregate([
{
$lookup: {
from: "customers",
localField: "customerId",
foreignField: "_id",
as: "customerInfo"
}
},
{
$unwind: "$customerInfo"
},
{
$project: {
_id: 1,
item: 1,
price: 1,
quantity: 1,
date: 1,
customerName: "$customerInfo.name",
customerAddress: "$customerInfo.address"
}
}
])
性能优化
- 索引:为经常用作过滤条件的字段创建索引,可以显著提高性能。
- 早期过滤:尽量在早期阶段使用
$match
来减少后续阶段需要处理的数据量。 - 限制输出字段:使用
$project
仅选择必要的字段,减少传输的数据量。 - 避免不必要的阶段:只包含实际需要的阶段,避免不必要的计算和转换。
通过合理地设计聚合管道,你可以高效地处理和分析大量数据。聚合框架提供了丰富的功能,使得 MongoDB 成为一个强大的数据分析工具。