$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 查询迁移进聚合管道时,先检查这几类操作符是否需要替换。