MongoDB(41)如何使用$group阶段?

5 阅读2分钟

在MongoDB中,使用 $group 阶段可以对文档进行分组和聚合。类似于SQL中的 GROUP BY 子句,$group 允许你根据某些字段对文档进行分组,并对每个组执行聚合操作(如求和、平均值、计数等)。

使用 $group 阶段的基本结构

{
  $group: {
    _id: <expression>,        // 分组条件
    <field1>: { <accumulator1>: <expression1> },  // 聚合字段
    <field2>: { <accumulator2>: <expression2> },
    // 其他聚合字段
  }
}
  • _id 是必须的,定义了分组的条件。
  • 聚合字段使用聚合操作符(如 $sum, $avg, $max, $min 等)进行计算。

代码示例

以下是使用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" },
            { customerId: 1, amount: 200, status: "pending" },
            { customerId: 2, amount: 150, status: "shipped" },
            { customerId: 2, amount: 50, status: "pending" },
            { customerId: 3, amount: 250, status: "shipped" }
        ]);

        console.log("Data inserted");
    } finally {
        await client.close();
    }
}

insertData().catch(console.error);

使用 $group 进行聚合

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');

        // 使用 $group 进行聚合,按照 customerId 分组并计算每个客户的订单总金额
        console.log("\n$group stage (sum of amount by customerId):");
        let result = await collection.aggregate([
            {
              $group: {
                _id: "$customerId",  // 按 customerId 分组
                totalAmount: { $sum: "$amount" }  // 计算每个组的 amount 总和
              }
            }
        ]).toArray();
        console.log(result);

        // 使用 $group 进行聚合,按照 status 分组并计算每个状态的订单数量和平均金额
        console.log("\n$group stage (count and avg amount by status):");
        result = await collection.aggregate([
            {
              $group: {
                _id: "$status",  // 按 status 分组
                count: { $sum: 1 },  // 计数每个组的文档数量
                avgAmount: { $avg: "$amount" }  // 计算每个组的 amount 平均值
              }
            }
        ]).toArray();
        console.log(result);

    } finally {
        await client.close();
    }
}

aggregateData().catch(console.error);

在这个示例中,我们演示了如何使用 $group 阶段进行聚合操作:

  1. 按照 customerId 分组并计算每个客户的订单总金额
  2. 按照 status 分组并计算每个状态的订单数量和平均金额

运行这个脚本后,你会得到如下结果(示例输出):

// sum of amount by customerId 结果
$group stage (sum of amount by customerId):
[
  { _id: 1, totalAmount: 300 },
  { _id: 2, totalAmount: 200 },
  { _id: 3, totalAmount: 250 }
]

// count and avg amount by status 结果
$group stage (count and avg amount by status):
[
  { _id: 'shipped', count: 3, avgAmount: 166.66666666666666 },
  { _id: 'pending', count: 2, avgAmount: 125 }
]

其他语言示例

类似的聚合操作也可以在其他编程语言中实现,如Python。以下是Python的示例代码:

安装PyMongo

在终端中运行以下命令来安装PyMongo:

pip install pymongo

使用Python进行聚合

from pymongo import MongoClient

def main():
    client = MongoClient('mongodb://localhost:27017/')
    db = client['myDatabase']
    collection = db['orders']

    # 使用 $group 进行聚合,按照 customerId 分组并计算每个客户的订单总金额
    print("\n$group stage (sum of amount by customerId):")
    pipeline = [
        {
          '$group': {
            '_id': "$customerId",  # 按 customerId 分组
            'totalAmount': { '$sum': "$amount" }  # 计算每个组的 amount 总和
          }
        }
    ]
    result = list(collection.aggregate(pipeline))
    for doc in result:
        print(doc)

    # 使用 $group 进行聚合,按照 status 分组并计算每个状态的订单数量和平均金额
    print("\n$group stage (count and avg amount by status):")
    pipeline = [
        {
          '$group': {
            '_id': "$status",  # 按 status 分组
            'count': { '$sum': 1 },  # 计数每个组的文档数量
            'avgAmount': { '$avg': "$amount" }  # 计算每个组的 amount 平均值
          }
        }
    ]
    result = list(collection.aggregate(pipeline))
    for doc in result:
        print(doc)

if __name__ == '__main__':
    main()

运行这个脚本后,你会得到类似的结果。通过这些示例,你可以了解到如何在不同编程语言中使用MongoDB的聚合管道进行分组和聚合操作,并根据各种条件进行数据聚合。

$group 示例进一步深入:

1. 计算总和

{
  $group: {
    _id: "$customerId",  // 按 customerId 分组
    totalAmount: { $sum: "$amount" }  // 计算每个组的 amount 总和
  }
}

2. 计算平均值

{
  $group: {
    _id: "$status",  // 按 status 分组
    avgAmount: { $avg: "$amount" }  // 计算每个组的 amount 平均值
  }
}

3. 计数文档

{
  $group: {
    _id: "$status",  // 按 status 分组
    count: { $sum: 1 }  // 计数每个组的文档数量
  }
}

4. 计算最大值和最小值

{
  $group: {
    _id: "$customerId",  // 按 customerId 分组
    maxAmount: { $max: "$amount" },  // 计算每个组的 amount 最大值
    minAmount: { $min: "$amount" }  // 计算每个组的 amount 最小值
  }
}

通过这些示例,你可以了解到如何在不同编程语言中使用MongoDB的聚合管道进行分组和聚合操作,并根据各种条件进行数据聚合。