阿里云主机折上折
  • 微信号
您当前的位置:网站首页 > 常用聚合阶段($match、$project、$group、$sort等)

常用聚合阶段($match、$project、$group、$sort等)

作者:陈川 阅读数:63244人阅读 分类: MongoDB

MongoDB的聚合管道是一种强大的数据处理工具,通过将多个阶段(stage)串联起来,可以对集合中的文档进行复杂的转换和分析。聚合阶段是管道的核心组成部分,每个阶段对输入文档进行处理,并将结果传递给下一个阶段。以下是几种常用的聚合阶段及其典型用法。

$match

$match 是聚合管道中常用的筛选阶段,类似于查询中的 find 方法。它允许我们根据条件过滤文档,只将符合条件的文档传递到下一个阶段。$match 应尽量放在管道的早期,以减少后续阶段需要处理的数据量。

db.orders.aggregate([
  { $match: { status: "completed", total: { $gt: 100 } } }
])

这个例子筛选出 status 为 "completed" 且 total 大于 100 的订单。$match 支持所有常规查询操作符,如 $eq$gt$in 等。

$project

$project 用于重塑文档结构,可以包含、排除字段,或创建新的计算字段。它是聚合管道中最灵活的阶段之一,常用于数据投影和转换。

db.users.aggregate([
  {
    $project: {
      name: 1,
      email: 1,
      yearOfBirth: { $year: "$birthDate" },
      fullName: { $concat: ["$firstName", " ", "$lastName"] }
    }
  }
])

这个例子从 users 集合中提取 nameemail 字段,同时计算 yearOfBirth 和拼接 fullName$project 还支持条件表达式(如 $cond)和数组操作(如 $slice)。

$group

$group 是聚合的核心阶段,用于按指定字段分组并计算聚合值。它可以与 $sum$avg$max$min 等累加器配合使用。

db.sales.aggregate([
  {
    $group: {
      _id: "$product",
      totalSold: { $sum: "$quantity" },
      averagePrice: { $avg: "$price" },
      maxQuantity: { $max: "$quantity" }
    }
  }
])

这个例子按 product 分组,计算每种产品的总销量、平均价格和最大单笔销量。$group_id 字段决定了分组依据,可以是单个字段、多个字段的组合或计算表达式。

$sort

$sort 对文档进行排序,可以指定一个或多个字段,并控制升序(1)或降序(-1)。它通常出现在管道的后期,用于最终结果的排序。

db.employees.aggregate([
  { $sort: { department: 1, salary: -1 } }
])

这个例子先按 department 升序排列,再按 salary 降序排列。$sort 会消耗较多内存,尤其是在处理大量数据时,可能需要增加 allowDiskUse 选项。

$limit 和 $skip

$limit 限制输出文档数量,$skip 跳过指定数量的文档。它们通常配合使用实现分页功能。

db.products.aggregate([
  { $skip: 20 },
  { $limit: 10 }
])

这个例子跳过前 20 个文档,返回接下来的 10 个文档。注意 $skip$limit 的顺序会影响结果。

$unwind

$unwind 展开数组字段,为数组中的每个元素创建一个单独的文档。它是处理数组数据的必备工具。

db.blogPosts.aggregate([
  { $unwind: "$comments" }
])

这个例子将 comments 数组展开,每个评论生成一个独立的文档。$unwind 还可以配合 preserveNullAndEmptyArrays 选项处理空数组或缺失字段的情况。

$lookup

$lookup 实现类似 SQL 的左连接(left outer join),可以从其他集合中查询并合并数据。

db.orders.aggregate([
  {
    $lookup: {
      from: "products",
      localField: "productId",
      foreignField: "_id",
      as: "productDetails"
    }
  }
])

这个例子将 ordersproducts 集合连接,通过 productId 匹配,结果存储在 productDetails 数组中。$lookup 还支持管道形式的复杂连接操作。

$addFields 和 $set

$addFields$set(MongoDB 4.2+)用于添加新字段或修改现有字段,而不改变其他字段。它们比 $project 更简洁,适合增量修改。

db.students.aggregate([
  {
    $addFields: {
      finalGrade: { $avg: ["$test1", "$test2", "$test3"] },
      passed: { $gte: [{ $avg: ["$test1", "$test2", "$test3"] }, 60] }
    }
  }
])

这个例子计算平均分并添加是否及格的标志。$set$addFields 的别名,功能完全相同。

$count

$count 返回管道中当前文档的数量,通常用于统计结果集的大小。

db.customers.aggregate([
  { $match: { city: "New York" } },
  { $count: "nyCustomers" }
])

这个例子统计纽约客户的数量,结果形式为 { nyCustomers: 123 }$count$group$project 组合的快捷方式。

$facet

$facet 允许在单个聚合管道中执行多个子管道,生成多组结果。它非常适合需要同时计算多种聚合指标的场景。

db.sales.aggregate([
  {
    $facet: {
      "totalSales": [{ $group: { _id: null, total: { $sum: "$amount" } } }],
      "topProducts": [
        { $group: { _id: "$product", count: { $sum: 1 } } },
        { $sort: { count: -1 } },
        { $limit: 5 }
      ],
      "monthlyTrend": [
        { $project: { month: { $month: "$date" } } },
        { $group: { _id: "$month", count: { $sum: 1 } } }
      ]
    }
  }
])

这个例子同时计算总销售额、最畅销的5个产品和月度销售趋势。$facet 的输出是一个文档,包含所有子管道的结果。

$bucket 和 $bucketAuto

$bucket$bucketAuto 将文档分组到指定的范围区间(桶)中。$bucket 需要明确指定边界,而 $bucketAuto 自动确定边界。

db.products.aggregate([
  {
    $bucket: {
      groupBy: "$price",
      boundaries: [0, 50, 100, 200, 500],
      default: "Other",
      output: {
        count: { $sum: 1 },
        averagePrice: { $avg: "$price" }
      }
    }
  }
])

这个例子按价格区间分组产品,统计每个区间的产品数量和平均价格。$bucketAuto 在不确定数据分布时特别有用。

$graphLookup

$graphLookup 实现递归查询,常用于处理树形或图状数据,如组织结构、社交网络等。

db.employees.aggregate([
  {
    $graphLookup: {
      from: "employees",
      startWith: "$reportsTo",
      connectFromField: "reportsTo",
      connectToField: "_id",
      as: "managementChain",
      maxDepth: 3
    }
  }
])

这个例子查找每个员工的管理链(向上3级)。$graphLookup 支持深度控制(maxDepth)和条件过滤(restrictSearchWithMatch)。

$merge 和 $out

$merge(MongoDB 4.2+)和 $out 将聚合结果写入集合。$out 完全替换目标集合,而 $merge 提供更灵活的写入选项(合并、替换、保留等)。

db.sales.aggregate([
  { $group: { _id: "$product", total: { $sum: "$amount" } } },
  { $merge: { into: "productTotals", on: "_id", whenMatched: "merge" } }
])

这个例子计算产品总销售额,并将结果合并到 productTotals 集合中。$merge 支持复杂的冲突处理策略。

本站部分内容来自互联网,一切版权均归源网站或源作者所有。

如果侵犯了你的权益请来信告知我们删除。邮箱:cc@cccx.cn

前端川

前端川,陈川的代码茶馆🍵,专治各种不服的Bug退散符💻,日常贩卖秃头警告级的开发心得🛠️,附赠一行代码笑十年的摸鱼宝典🐟,偶尔掉落咖啡杯里泡开的像素级浪漫☕。‌