在上一篇文章【 MongoDB聚合管道实战(二):$group操作符的应用与技巧】中,展示了来分析销售数据,计算每天的销售总额,并找出销售额最高的日期。利用group、sort、limit 等聚合操作符,可以方便地进行数据分析与处理,满足具体的业务需求。本文中,我们将探讨如何利用MongoDB的聚合管道group、unwind、project操作符来实现这样的高级功能。
知识回顾
知识回顾
MongoDB 的聚合管道提供了一系列强大的操作符,用于处理和分析数据。以下是一些常用的聚合阶段及其介绍:
1. $match
-
功能:过滤文档以指定条件。
-
使用场景:在数据流经过管道时,选择符合条件的文档进行后续处理。
-
示例:
{ $match: { status: "active" } }
2. $group
-
功能:将多个文档分组,并对每个组进行聚合操作(例如求和、计数等)。
-
使用场景:进行汇总计算,如计算总销售额、平均值等。
-
示例:
{ $group: { _id: "$customer_id", totalSales: { $sum: "$amount" } } }
3. $sort
-
功能:对文档进行排序。
-
使用场景:根据特定字段的值进行升序或降序排序。
-
示例:
{ $sort: { totalSales: -1 } } // 降序排序
4. $project
-
功能:选择、重命名或计算字段。
-
使用场景:输出所需的字段,进行字段的格式化或计算。
-
示例:
{ $project: { stu_name: 1, averageScore: { $avg: "$scores" } } }
5. $limit
-
功能:限制返回的文档数量。
-
使用场景:控制输出结果集的大小。
-
示例:
{ $limit: 5 }
6. $skip
-
功能:跳过指定数量的文档。
-
使用场景:常用于分页,跳过前面的文档。
-
示例:
{ $skip: 10 }
7. $unwind
-
功能:将数组字段拆分为多条文档,每个文档只包含数组中的一个元素。
-
使用场景:处理文档中包含数组字段的情况,便于进一步分析。
-
示例:
{ $unwind: "$items" }
8. $addFields
-
功能:向文档添加新字段或更新现有字段。
-
使用场景:在管道中动态计算和添加字段。
-
示例:
{ $addFields: { totalPrice: { $multiply: ["$price", "$quantity"] } } }
9. $replaceRoot
-
功能:替换输入文档为指定文档。
-
使用场景:当需要将嵌套文档提升为根文档时使用。
-
示例:
{ $replaceRoot: { newRoot: "$details" } }
10. $facet
-
功能:进行多管道并行处理,可以在同一集合上进行不同的聚合查询。
-
使用场景:在一个聚合操作中获得多个不同的结果。
-
示例:
{ $facet: { totalSales: [{ $group: { _id: null, total: { $sum: "$amount" } }}], averageSales: [{ $group: { _id: null, average: { $avg: "$amount" } }}] } }
11. $lookup
-
功能:进行集合间的连接操作(类似 SQL 的 JOIN)。
-
使用场景:将来自其他集合的数据合并到当前文档。
-
示例:
{ $lookup: { from: "customers", localField: "customer_id", foreignField: "_id", as: "customerInfo" } }
任务描述
假设有一个 orders 集合,记录每个客户的订单信息。每个订单包含客户的 customer_id、items(一个数组,记录订单中的多个商品)、订单的 total(订单总金额)等字段。我们希望计算每位客户的总消费金额以及他们购买的商品种类数量。
数据结构
{
"_id": ObjectId("..."),
"customer_id": "C001",
"items": [
{ "product": "Apple", "price": 1.5 },
{ "product": "Banana", "price": 0.5 }
],
"total": 2.0
}
任务准备
首先,我们需要插入一些示例数据:
db.orders.insertMany([
{
customer_id: "C001",
items: [
{ product: "Apple", price: 1.5 },
{ product: "Banana", price: 0.5 }
],
total: 2.0
},
{
customer_id: "C002",
items: [
{ product: "Orange", price: 1.0 },
{ product: "Banana", price: 0.5 }
],
total: 1.5
},
{
customer_id: "C001",
items: [
{ product: "Peach", price: 2.0 },
{ product: "Apple", price: 1.5 }
],
total: 3.5
},
{
customer_id: "C003",
items: [
{ product: "Banana", price: 0.5 },
{ product: "Grapes", price: 2.0 }
],
total: 2.5
}
]);
任务实施
聚合管道实现
我们将使用以下聚合管道来计算每位客户的总消费金额以及他们购买的商品种类数量:
db.orders.aggregate([
{
$unwind: "$items" // 将 items 数组拆分为多条文档
},
{
$group: {
_id: "$customer_id", // 以 customer_id 分组
totalSpent: { $sum: "$total" }, // 计算每个客户的总消费金额
uniqueItems: { $addToSet: "$items.product" } // 统计每位客户购买的不同商品
}
},
{
// 计算每位客户购买的商品种类数量
$project: {
_id: 1,
totalSpent: 1,
itemCount: { $size: "$uniqueItems" } // 获取不同商品数量
}
}
]);
CopyInsert
聚合管道分解
-
$unwind:
- 通过
$unwind操作符将items数组拆分为多条文档,每个文档代表一个商品,使得我们可以单独处理每个商品。
- 通过
-
$group:
"_id": "$customer_id":根据客户 ID 进行分组。totalSpent: { $sum: "$total" }:计算每位客户的总消费金额。uniqueItems: { $addToSet: "$items.product" }:使用$addToSet统计客户购买的不同商品,避免重复。
-
$project:
- 使用
$project自定义输出。保留_id和totalSpent字段,同时计算每位客户购买的商品种类数量,使用$size来获取数组长度。
- 使用
执行结果
执行上述聚合管道后,您将获得类似的结果:
[ { "_id": "C001", "totalSpent": 5.5, "itemCount": 3 }, { "_id": "C002", "totalSpent": 1.5, "itemCount": 2 }, { "_id": "C003", "totalSpent": 2.5, "itemCount": 2 }]
这表明客户 C001 的总消费为 5.5,购买的商品种类为 3;客户 C002 和 C003 的总消费和商品种类数量也获得了相应的统计。
实验实训
使用聚合管道中的 $unwind、$group 和 $project 等操作符使用。
总结
通过以上案例,我们展示了如何使用 MongoDB 的聚合管道聚合管道来计算每位客户的总消费金额以及他们购买的商品种类数量。利用聚合管道中的 $group、$sort 和 $limit 等操作符,可以方便地进行数据分析与处理,满足具体的业务需求。这种灵活性使得 MongoDB 成为处理复杂数据分析任务的理想选择。下一篇我们继续讲解聚合表达式的综合应用。