MongoDB 的聚合管道(aggregation pipeline)是一系列用于处理数据流的阶段(stages)。每个阶段都会接收一个输入文档流,并生成一个新的输出文档流传递给下一个阶段。这使得你可以组合多个操作来完成复杂的数据处理任务。
聚合管道的组成部分
一个聚合管道通常包含以下几个部分:
- 输入文档:从集合中读取的文档。
- 聚合阶段:对输入文档进行处理的步骤。
- 输出文档:经过所有阶段处理后的最终文档。
常见的聚合阶段
这里列出了一些常见的聚合阶段:
- $match:过滤文档,只输出那些匹配指定条件的文档。
- $group:按指定的表达式分组文档,并可以计算聚合值,例如求和、平均数等。
- $sort:对文档排序。
- $project:修改输出文档的结构,可以选择性地排除或包含某些字段,并可以添加计算字段。
- $lookup:执行左外连接(left outer join),从其他集合中获取文档,并将其添加到输出文档中。
- $unwind:将文档中的数组字段拆分成多个文档,每个文档包含数组中的一个元素。
- $limit:限制输出文档的数量。
- $skip:跳过指定数量的文档。
- $redact:根据条件从文档中删除字段。
示例
让我们通过一些具体的例子来说明这些阶段是如何使用的。
示例 1: 使用 $group 来统计每个用户的订单数量
假设我们有一个名为 orders
的集合,其中包含每个订单的信息,比如 userId
, orderDate
, totalPrice
等字段。我们想要统计每个用户的订单数量。
db.orders.aggregate([
{
$group: {
_id: "$userId",
totalOrders: { $sum: 1 }
}
}
])
示例 2: 使用 $lookup 来关联两个集合
如果我们要获取每个订单的用户信息,假设用户信息存储在 users
集合中,每个用户有 userId
, firstName
, lastName
等字段。
db.orders.aggregate([
{
$lookup: {
from: "users",
localField: "userId",
foreignField: "userId",
as: "userDetails"
}
},
{
$unwind: "$userDetails"
},
{
$project: {
userId: 1,
orderDate: 1,
totalPrice: 1,
firstName: "$userDetails.firstName",
lastName: "$userDetails.lastName"
}
}
])
示例 3: 使用 $match 和 $sort 来过滤和排序数据
假设我们需要找到所有总价超过 100 元的订单,并按照总价降序排列。
db.orders.aggregate([
{
$match: {
totalPrice: { $gt: 100 }
}
},
{
$sort: {
totalPrice: -1
}
}
])
复杂的聚合管道
聚合管道可以包含多个阶段,你可以根据需要组合这些阶段来实现复杂的逻辑。例如,我们可能想要找出每个用户的最近一笔订单,并且只考虑总价超过 100 元的订单。
db.orders.aggregate([
{
$match: {
totalPrice: { $gt: 100 }
}
},
{
$sort: {
orderDate: -1
}
},
{
$group: {
_id: "$userId",
latestOrder: { $first: "$$ROOT" }
}
},
{
$replaceRoot: {
newRoot: "$latestOrder"
}
}
])
在这个例子中,我们首先使用 $match
阶段来过滤出总价超过 100 元的订单。然后,使用 $sort
阶段按照 orderDate
字段降序排序。接着,使用 $group
阶段按 userId
分组,并使用 $first
运算符来获取每个用户的最近一笔订单。最后,使用 $replaceRoot
阶段将根文档替换为最新的订单文档。
使用 Node.js 进行聚合
在 Node.js 中,你可以使用 MongoDB 客户端驱动来执行聚合查询。下面是一个简单的示例:
const MongoClient = require('mongodb').MongoClient;
const uri = "your_connection_string_here";
const client = new MongoClient(uri, { useNewUrlParser: true, useUnifiedTopology: true });
client.connect(async err => {
const collection = client.db("test").collection("orders");
const result = await collection.aggregate([
// 添加你的聚合阶段
]).toArray();
console.log(result);
client.close();
});
如果你需要进一步的帮助或具体的代码示例,请告诉我。