MongoDB聚合查询实例:统计分析用户数据

在MongoDB中,聚合查询(Aggregation)是一种强大的数据处理工具,它允许我们对集合中的文档进行多阶段的转换和分析,就像流水线一样处理数据。比如统计不同地区的用户数量、计算用户平均年龄、分析订单总金额等,这些都可以通过聚合管道轻松实现。

准备示例数据

为了方便理解,我们假设一个用户数据集合users,每个用户文档结构如下(简化版):

{
  "_id": ObjectId("..."),
  "name": "张三",
  "age": 25,
  "gender": "男",
  "region": "北京",
  "orders": [
    { "amount": 100, "date": "2023-01-01" },
    { "amount": 150, "date": "2023-02-15" }
  ]
}

包含的字段:姓名(name)、年龄(age)、性别(gender)、地区(region)、订单数组(orders,每个订单有金额amount和日期date)。

基础聚合阶段介绍

MongoDB聚合管道由多个阶段(Stage) 组成,每个阶段处理数据的一个操作,前一个阶段的输出作为下一个阶段的输入。常用阶段和操作符:
- $match:过滤文档(类似SQL的WHERE)
- $group:按指定字段分组,配合累加器(如$sum$avg)统计结果
- $project:只保留需要的字段(类似SQL的SELECT)
- $sort:按指定字段排序(类似SQL的ORDER BY)
- $unwind:展开数组字段(如将orders数组拆分为多个文档)
- 累加器操作符$sum(求和)、$avg(平均值)、$max(最大值)、$min(最小值)

实例1:统计每个性别的用户数量

需求:统计“男”“女”用户各有多少人。

聚合管道

db.users.aggregate([
  {
    $group: {
      _id: "$gender",  // 按gender字段分组
      count: { $sum: 1 }  // 每个分组的文档数+1(即统计数量)
    }
  },
  {
    $sort: { count: -1 }  // 按数量降序排序
  }
])

解释
- $group:按gender分组,_id指定分组字段,count是统计结果字段,$sum:1表示每个文档加1(即每个用户算1次)。
- $sort:按count降序排列,让结果更直观。

输出示例

[
  { "_id": "男", "count": 120 },
  { "_id": "女", "count": 80 }
]

实例2:统计各地区用户的平均年龄

需求:计算每个地区用户的平均年龄(忽略年龄为null的用户)。

聚合管道

db.users.aggregate([
  {
    $match: { age: { $exists: true } }  // 过滤掉age不存在的用户
  },
  {
    $group: {
      _id: "$region",  // 按地区分组
      avg_age: { $avg: "$age" }  // 计算该地区用户的平均年龄
    }
  },
  {
    $project: {  // 只保留需要的字段,隐藏_id
      region: "$_id",
      avg_age: 1,
      _id: 0
    }
  },
  {
    $sort: { avg_age: -1 }  // 按平均年龄降序排列
  }
])

解释
- $match:用$exists: true过滤掉没有年龄数据的用户,避免$avg计算错误。
- $group$avg: "$age"计算分组内的平均年龄(自动忽略null/不存在的字段)。
- $project:将_id重命名为region,并隐藏原始_id,结果更清晰。

实例3:统计每个用户的总消费金额

需求:用户可能有多个订单,需要统计每个用户的订单总金额。

聚合管道

db.users.aggregate([
  {
    $unwind: "$orders"  // 展开orders数组,每个订单拆分为独立文档
  },
  {
    $group: {
      _id: "$_id",  // 按用户ID分组(即每个用户)
      total_amount: { $sum: "$orders.amount" }  // 累加每个订单的金额
    }
  },
  {
    $sort: { total_amount: -1 },  // 按总金额降序排列
    $limit: 10  // 只取消费最高的前10个用户
  }
])

解释
- $unwind: "$orders":将orders数组中的每个元素拆分为独立文档(例如一个用户有2个订单,拆分为2个文档)。
- $group:按用户_id分组,累加每个订单的amount金额。
- $limit: 10:只取前10条结果(可配合$skip实现分页,如$skip: 20跳过前20条)。

实例4:统计各地区用户数量、平均年龄、最大年龄

需求:同时统计每个地区的用户数、平均年龄和最大年龄。

聚合管道

db.users.aggregate([
  {
    $group: {
      _id: "$region",
      user_count: { $sum: 1 },
      avg_age: { $avg: "$age" },
      max_age: { $max: "$age" }
    }
  },
  {
    $sort: { user_count: -1 }
  }
])

解释
- $group中可以同时使用多个累加器:$sum:1统计用户数,$avg: "$age"计算平均年龄,$max: "$age"取最大年龄。
- 结果会包含每个地区的user_countavg_agemax_age三个字段。

总结

MongoDB聚合查询通过管道式阶段实现灵活的数据处理,适合初学者的核心操作包括:
1. 过滤:用$match缩小数据范围(类似SQL的WHERE)。
2. 分组统计:用$group+累加器($sum/$avg等)实现统计。
3. 字段处理:用$project隐藏不需要的字段,结果更简洁。
4. 排序/分页:用$sort$limit/$skip控制结果顺序和数量。

建议从简单分组统计开始练习,逐步尝试复杂场景(如多层嵌套聚合、数组处理等)。遇到问题可参考MongoDB官方文档的聚合管道语法(https://docs.mongodb.com/manual/reference/operator/aggregation/),多动手写代码验证结果!

小夜