在MongoDB中,聚合操作通过管道的方式将多个阶段(stages)串联在一起,每个阶段对文档进行特定的处理。以下是聚合操作中常见的阶段及其详细解释,每个阶段还将附带代码示例。
常见的聚合阶段
- $match:过滤文档,条件类似于
find查询。 - $group:将文档分组,并可进行计算(如求和、平均值、计数等)。
- $sort:对文档进行排序。
- $project:重新定义文档结构,可用于选择、计算和重命名字段。
- $limit:限制返回的文档数量。
- $skip:跳过指定数量的文档。
- $unwind:将数组字段拆分成独立的文档。
- $lookup:进行集合间的连接操作。
- $addFields:添加新的字段到文档中。
- $replaceRoot:替换输入文档为指定的字段。
代码示例
以下是使用Node.js进行各个阶段的代码示例。首先确保安装了MongoDB的Node.js驱动:
npm install mongodb
插入示例数据
const { MongoClient } = require('mongodb');
async function insertData() {
const uri = "mongodb://localhost:27017";
const client = new MongoClient(uri, { useUnifiedTopology: true });
try {
await client.connect();
const db = client.db('myDatabase');
const collection = db.collection('orders');
await collection.deleteMany({}); // 清空集合
await collection.insertMany([
{ customerId: 1, amount: 100, status: "shipped", items: [{ product: "A", qty: 2 }, { product: "B", qty: 1 }] },
{ customerId: 1, amount: 200, status: "pending", items: [{ product: "B", qty: 4 }] },
{ customerId: 2, amount: 150, status: "shipped", items: [{ product: "A", qty: 1 }] },
{ customerId: 2, amount: 50, status: "pending", items: [{ product: "C", qty: 2 }] },
{ customerId: 3, amount: 250, status: "shipped", items: [{ product: "D", qty: 3 }] }
]);
console.log("Data inserted");
} finally {
await client.close();
}
}
insertData().catch(console.error);
使用聚合管道
async function aggregateData() {
const uri = "mongodb://localhost:27017";
const client = new MongoClient(uri, { useUnifiedTopology: true });
try {
await client.connect();
const db = client.db('myDatabase');
const collection = db.collection('orders');
// $match
console.log("\n$match stage:");
let result = await collection.aggregate([
{ $match: { status: "shipped" } }
]).toArray();
console.log(result);
// $group
console.log("\n$group stage:");
result = await collection.aggregate([
{ $group: { _id: "$customerId", totalAmount: { $sum: "$amount" } } }
]).toArray();
console.log(result);
// $sort
console.log("\n$sort stage:");
result = await collection.aggregate([
{ $sort: { amount: -1 } }
]).toArray();
console.log(result);
// $project
console.log("\n$project stage:");
result = await collection.aggregate([
{ $project: { customerId: 1, amount: 1, status: 1, _id: 0 } }
]).toArray();
console.log(result);
// $limit
console.log("\n$limit stage:");
result = await collection.aggregate([
{ $limit: 2 }
]).toArray();
console.log(result);
// $skip
console.log("\n$skip stage:");
result = await collection.aggregate([
{ $skip: 2 }
]).toArray();
console.log(result);
// $unwind
console.log("\n$unwind stage:");
result = await collection.aggregate([
{ $unwind: "$items" }
]).toArray();
console.log(result);
// $lookup
await db.collection('customers').deleteMany({}); // 清空集合
await db.collection('customers').insertMany([
{ _id: 1, name: "Customer 1" },
{ _id: 2, name: "Customer 2" },
{ _id: 3, name: "Customer 3" }
]);
console.log("\n$lookup stage:");
result = await collection.aggregate([
{
$lookup: {
from: "customers",
localField: "customerId",
foreignField: "_id",
as: "customerDetails"
}
}
]).toArray();
console.log(result);
// $addFields
console.log("\n$addFields stage:");
result = await collection.aggregate([
{ $addFields: { discount: { $cond: { if: { $gte: ["$amount", 200] }, then: 20, else: 0 } } } }
]).toArray();
console.log(result);
// $replaceRoot
console.log("\n$replaceRoot stage:");
result = await collection.aggregate([
{ $replaceRoot: { newRoot: { customerId: "$customerId", totalAmount: "$amount" } } }
]).toArray();
console.log(result);
} finally {
await client.close();
}
}
aggregateData().catch(console.error);
在这段代码中,我们演示了如何使用聚合管道的各个阶段来处理数据:
- $match:过滤出
status为shipped的订单。 - $group:按
customerId分组并计算总金额。 - $sort:按
amount字段降序排序。 - $project:选择
customerId、amount和status字段,排除_id字段。 - $limit:限制返回的文档数量为2。
- $skip:跳过前两个文档。
- $unwind:将
items数组拆分成独立的文档。 - $lookup:连接
customers集合,添加customerDetails字段。 - $addFields:添加新的字段
discount,根据amount的值设置折扣。 - $replaceRoot:用新的根字段替换文档的根。
总结
聚合管道是MongoDB中非常强大的工具,能够通过多个阶段对数据进行复杂的处理和转换。通过上述代码示例,你可以了解如何在Node.js中使用聚合管道的常见阶段,来实现数据的过滤、分组、排序、投影、限制、跳过、拆分、连接、添加字段和替换根等操作。这些阶段提供了丰富的功能,能够满足各种复杂的数据处理需求。