首页/数据/NoSQL 速查/聚合 $match 过滤阶段
MongoDB99 条

聚合 $match 过滤阶段

$match 用与 find 相同的过滤语法在管道内筛文档;作为首阶段时能直接利用索引,是聚合性能的主要抓手。

NoSQL 速查数据更新于 2026-10-13

$match 是什么

$match 是聚合管道中的过滤阶段,条件语法与 find 完全一致,用来在管道里筛掉不需要的文档。它的性能意义大于语法意义:放在管道首阶段时和 find 一样能利用索引,一旦挪到 $group、$unwind 之后,前面的计算就全部白做,只是把结果丢弃。

基本信息

语法{ $match: { <查询条件> } }
条件写法与 find 一致:比较、逻辑、$in、$elemMatch 等操作符可直接复用
索引利用作为首阶段时与 find 同等利用索引
位置建议尽量放在管道最前,过滤优先于计算
限制不支持 $where;$text 只能出现在首阶段且仅一次

典型使用场景

  • 聚合前先按时间范围与状态缩小数据集,避免全量文档进入管道
  • 分阶段过滤:数组 $unwind 展开后再按元素条件筛一层
  • 配合 $lookup 关联时先过滤主表,减少参与关联的文档数
  • 多条件权限过滤:按租户、状态、时间同时限定范围
  • 分页查询:与 $sort、$skip、$limit 组合时 $match 必须写在最前

常用写法

常用写法
// 首阶段过滤:能走索引,先把数据量压下来
 db.orders.aggregate([
   { $match: { ts: { $gte: ISODate("2026-10-01T00:00:00Z") }, status: "paid" } },
   { $group: { _id: "$sku", qty: { $sum: "$qty" } } },
   { $sort: { qty: -1 } },
   { $limit: 10 }
 ])

// 展开数组后再按元素条件过滤
 db.orders.aggregate([
   { $match: { status: "paid" } },
   { $unwind: "$items" },
   { $match: { "items.qty": { $gt: 5 } } }
 ])

// 查看执行计划,确认首阶段 $match 是否命中索引
 db.orders.explain("executionStats").aggregate([{ $match: { status: "paid" } }])

$match 与 find 的差异

对比项$match 行为注意
条件语法与 find 一致既有查询操作符可直接复用
索引利用仅首阶段可利用放在 $group 之后退化为内存过滤
$where不支持需要脚本逻辑时改用 $expr 或前置处理
$text支持,但必须位于首阶段且仅出现一次多个全文条件要合并成一条
$expr支持,可比较同一文档内两个字段跨字段比较只能这样写
$match 的条件语法与 find 基本一致但并非完全等价:$where 在聚合中不可用,$text 有位置与次数限制。把 find 查询迁移进聚合管道时,先检查这几类操作符是否需要替换。

易错点

  • 把 $match 放到 $group 之后,前面会先对全量数据分组计算再整批丢弃,CPU 与内存开销成倍上升
  • 期望 $match 顺带做类型转换:字段存成字符串时数值范围比较不会命中,需要 $expr 或先 $convert
  • $match 中使用 $text 又放在管道中段,查询会直接报错而不是自动降级执行
  • 分页场景把 $match 写在 $skip 之后,先分页再过滤的语义被破坏,返回条数与调用方预期不符

数据来源与参考

  • MongoDB Manual: $match
​‌‌​​‌​​​‌‌​‌‌‌‌​‌‌​​​‌‌​‌‌‌​​‌‌​​‌​‌‌‌​​‌‌‌​​​‌​‌‌​‌​​‌​‌‌‌​​​‌​‌‌​‌​​‌​‌‌​​​‌‌​‌‌‌​‌​​​‌‌​‌‌‌‌​​‌​‌‌‌​​‌‌​​​‌‌​‌‌​‌‌‌‌​‌‌​‌‌​‌