MongoDB Academy · 课时

$sum、$avg、$min、$max:数值聚合

您将使用 $group 计算总和、平均值和极值,并在 $project 中将这些累加器用作表达式运算符。

第 1 / 4 课13 个步骤

$sum、$avg、$min、$max:数值聚合 是 CoddyKit 上的免费 MongoDB Academy 课时。 这是第 1 节课,共 4 节。 你可以在下方免费阅读本课时的完整内容 — 然后在浏览器中使用内置代码编辑器和全天候 AI 导师进行实践。 这是 MongoDB Academy 学习路径的一部分,你的进度在网页和 CoddyKit 应用中同步。 MongoDB Academy 课程共包含 4 节课。

$group 中的数值累加器

MongoDB 的 $group 阶段使用累加器从分组文档中计算聚合值。最基本的数值累加器是 $sum、$avg、$min 和 $max。每个累加器都会处理一个分组中的所有文档,并生成一个输出值。这些运算符是分析流水线的基础。

使用 $sum 进行计数和求和

$sum 累加器有两种常见用途:传入 1 这样的字面值来统计文档数量,以及引用数值字段来计算字段总和。当字段缺失或为 null 时,$sum 会将其视为零。因此,在可选数值字段上使用它时无需额外进行 null 检查,也很安全。

db.orders.aggregate([
  {
    $group: {
      _id: '$status',
      orderCount: { $sum: 1 },
      totalRevenue: { $sum: '$amount' }
    }
  }
])

使用 $avg 计算平均值

$avg 累加器会计算分组中所有文档的某个数值字段的算术平均值。对于字段缺失或为 null 的文档,它会自动忽略,只根据有效值计算平均值。这对于计算每个产品的平均订单金额或平均评分等指标非常有用。

db.reviews.aggregate([
  {
    $group: {
      _id: '$productId',
      averageRating: { $avg: '$rating' },
      reviewCount: { $sum: 1 }
    }
  },
  { $sort: { averageRating: -1 } }
])

使用 $min 和 $max 查找极值

$min 和 $max 分别返回分组中的最小值和最大值。它们适用于任何可比较的类型,例如数字、日期和字符串。常见用途包括查找一次会话中的第一个和最后一个事件时间,或某个类别中价格最低和最高的产品。它们会忽略 null 值和缺失值。

db.sessions.aggregate([
  {
    $group: {
      _id: '$userId',
      firstLogin: { $min: '$timestamp' },
      lastLogin: { $max: '$timestamp' },
      minSessionDuration: { $min: '$durationSeconds' },
      maxSessionDuration: { $max: '$durationSeconds' }
    }
  }
])

按 Null 分组以计算全局总计

要计算整个集合的单个聚合结果,请将 _id 设置为 null。这样会将所有文档分到同一个组中。借助这一技术,您可以在不划分数据的情况下计算总计、总体平均值和全局极值。您可以将其理解为没有 GROUP BY 子句的 SQL SELECT SUM(*) FROM orders 在 MongoDB 中的对应写法。

db.orders.aggregate([
  {
    $group: {
      _id: null,
      totalOrders: { $sum: 1 },
      grandTotal: { $sum: '$amount' },
      averageOrder: { $avg: '$amount' },
      minOrder: { $min: '$amount' },
      maxOrder: { $max: '$amount' }
    }
  }
])

在 $project 中使用这些累加器

一个不太为人熟知的功能是,$sum、$avg、$min 和 $max 也可以在 $project 中作为表达式运算符使用,而不仅限于 $group。在这种情况下,它们处理的是单个文档中的数组,而不是多个文档。这使您无需使用 $group 阶段,就能计算嵌入式数组字段中各元素的总和。

db.carts.aggregate([
  {
    $project: {
      userId: 1,
      // Sum elements inside the items array
      cartTotal: { $sum: '$items.price' },
      maxItemPrice: { $max: '$items.price' },
      avgItemPrice: { $avg: '$items.price' }
    }
  }
])

累加器中的嵌套表达式

累加器接受任何有效表达式,而不仅仅是字段引用。您可以在累加器中使用算术运算符、条件表达式,甚至使用 $cond。这样,您就能在单个流水线阶段中实现条件求和,例如“只对已完成的订单求和”或“只统计高价值交易”。

db.orders.aggregate([
  {
    $group: {
      _id: '$customerId',
      // Only sum orders that are 'completed'
      completedRevenue: {
        $sum: {
          $cond: [
            { $eq: ['$status', 'completed'] },
            '$amount',
            0
          ]
        }
      }
    }
  }
])

多级分组流水线

您可以串联多个 $group 阶段来计算多级聚合。第一个分组计算每天的总计,第二个分组再根据这些每日总计计算月平均值。与将所有操作放在一个阶段中相比,这种模式更清晰,也更容易理解流水线逻辑。

db.sales.aggregate([
  // First group: totals per day
  {
    $group: {
      _id: { year: { $year: '$date' }, month: { $month: '$date' }, day: { $dayOfMonth: '$date' } },
      dailyTotal: { $sum: '$amount' }
    }
  },
  // Second group: average daily total per month
  {
    $group: {
      _id: { year: '$_id.year', month: '$_id.month' },
      avgDailyRevenue: { $avg: '$dailyTotal' },
      totalMonthRevenue: { $sum: '$dailyTotal' }
    }
  }
])

使用 $match 在分组前筛选

请始终将 $match 阶段放在 $group之前,先筛选出相关文档。这样可以减少分组阶段需要处理的文档数量,更重要的是,还允许 MongoDB 使用索引来完成筛选。$group 之后的 $match 会筛选分组结果,这同样很有用,但无法利用索引。

db.orders.aggregate([
  // Filter first — MongoDB can use an index on createdAt
  {
    $match: {
      createdAt: { $gte: new Date('2024-01-01') },
      status: 'completed'
    }
  },
  {
    $group: {
      _id: '$region',
      totalRevenue: { $sum: '$amount' },
      avgRevenue: { $avg: '$amount' }
    }
  },
  { $sort: { totalRevenue: -1 } }
])

处理缺失值和 Null 值

当 $sum 或 $avg 引用的字段缺失或为 null 时,两者的行为略有不同。$sum 会将缺失值或 null 视为零,因此所有文档都会计入计数。$avg 以及 $min/$max 会完全忽略缺失值或 null,它们不会参与计算。理解这一差异有助于避免分析查询中的隐蔽错误。

// Consider documents where some lack a 'discount' field
// $sum: missing = 0, so it counts in the total
// $avg: missing fields are ignored, avg is over existing values only
db.orders.aggregate([
  {
    $group: {
      _id: '$category',
      totalDiscount: { $sum: '$discount' }, // missing = 0
      avgDiscount: { $avg: '$discount' }    // missing = ignored
    }
  }
])

实践示例:销售仪表板

在一个 $group 阶段中组合使用 $sum、$avg、$min 和 $max,是计算仪表板指标的常见模式。单个聚合流水线即可返回填充摘要卡片所需的全部内容:订单总数、收入、平均订单金额以及订单金额范围。这样可以避免多次往返访问数据库。

db.orders.aggregate([
  { $match: { status: 'completed' } },
  {
    $group: {
      _id: '$category',
      totalOrders: { $sum: 1 },
      totalRevenue: { $sum: '$amount' },
      avgOrderValue: { $avg: '$amount' },
      smallestOrder: { $min: '$amount' },
      largestOrder: { $max: '$amount' }
    }
  },
  { $sort: { totalRevenue: -1 } },
  { $limit: 10 }
])

快速检查

测试您对本课 MongoDB 和 NoSQL 数据库相关概念的理解。

课程回顾

在本课中,您学习了:$sum 会对值求和并统计文档数量(缺失值 = 0),$avg/$min/$max 会忽略缺失字段或 null 字段,以及这些累加器既可以在 $group 中跨文档使用,也可以在 $project 中处理数组。接下来,我们将学习如何使用 $push 和 $addToSet 在分组中构建数组。

免费开始

用 AI 导师学习 JavaScript — 免费

在浏览器中编写并运行真实代码,获得全天候 AI 导师的即时帮助,并在网页或应用中继续学习。

课程
30
课程
120

常见问题解答

「$sum、$avg、$min、$max:数值聚合」课时是免费的吗?

是的 — 「$sum、$avg、$min、$max:数值聚合」的完整文本可在网页上免费阅读。要进行交互式练习(内置代码编辑器和全天候 AI 导师)并解锁 MongoDB Academy 课程的其余内容,请升级到 CoddyKit PRO。 MongoDB Academy 课程共包含 4 节课。

「$sum、$avg、$min、$max:数值聚合」这节课中我会学到什么?

您将使用 $group 计算总和、平均值和极值,并在 $project 中将这些累加器用作表达式运算符。 你通过在浏览器中直接运行的动手代码来练习 MongoDB Academy,全天候 AI 导师会在你学习这节课的过程中回答你的问题。

学习 MongoDB Academy 需要有经验吗?

无需任何先前经验。CoddyKit 上的 MongoDB Academy 课程适合初学者到高级学习者,你可以从这里开始或从头开始,按照自己的节奏学习。 这是第 1 节课,共 4 节。

「$sum、$avg、$min、$max:数值聚合」课时需要多长时间?

大多数 CoddyKit 课程大约需要 5–10 分钟。每节课都很精短且互动,所以你能稳步进步,并在网页和应用中从离开的地方继续。

我能在这节 MongoDB Academy 课中编写并运行代码吗?

能。每节 MongoDB Academy 课都包含内置代码编辑器,你可以在浏览器中直接编写并运行真实代码,并获得即时 AI 反馈 — 无需本地设置。

此课程中的所有课时

  1. $sum、$avg、$min、$max:数值聚合
  2. $push 和 $addToSet:在分组中构建数组
  3. $first、$last 以及 $top/$bottom 累加器
  4. 使用 $setWindowFields 进行窗口函数计算
← 返回 MongoDB Academy