管道里的条件表达式
聚合管道的条件表达式的用途是「算出一个值」而不是「过滤文档」:$cond 做二选一分支,$ifNull 给空值兜底,$switch 处理多分支。它们常出现在 $project 与 $addFields 里,用于打标、分档、补齐缺省值与容错,让输出结构直接可用。
基本信息
| $cond | { $cond: { if, then, else } } 或数组写法 [条件, 真值, 假值] |
|---|---|
| $ifNull | { $ifNull: [值, 兜底值] },也可以提供多个候选值 |
| $switch | { $switch: { branches: [ { case, then } ], default } } |
| 适用位置 | $project、$addFields、$group 的累加表达式等 |
| 与查询条件区别 | 条件表达式不参与筛选,过滤仍要靠 $match |
典型使用场景
- 分档打标:按金额或数量划分等级,输出枚举值供报表使用
- 空值兜底:字段缺失或为 null 时统一填充占位值,避免前端出现空单元格
- 多分支映射:按状态码或渠道映射为可读文案
- 容错计算:分母为 0 时避免除零,返回空值或 0
- 结构化输出:把多个字段拼成嵌套结构,减少应用层处理
示例
示例
db.orders.aggregate([
{ $project: {
sku: 1,
// 二选一分支:数量达到 100 记为 A 档
grade: { $cond: [{ $gte: ["$qty", 100] }, "A", "B"] },
// 空值兜底:备注缺失时输出占位符
note: { $ifNull: ["$remark", "-"] },
// 多分支:按状态码映射为可读文案,命中即停
statusText: { $switch: { branches: [
{ case: { $eq: ["$status", 1] }, then: "待付款" },
{ case: { $eq: ["$status", 2] }, then: "已付款" }
], default: "其他" } },
// 容错:分母为 0 时给出 0,避免除零得到 null
ratio: { $cond: [{ $eq: ["$total", 0] }, 0, { $divide: ["$done", "$total"] }] }
} }
])表达式读法
| 表达式 | 求值规则 | 注意点 |
|---|---|---|
| $cond(对象写法) | 条件为真取 then,否则取 else | else 可省略,省略时结果为缺失 |
| $cond(数组写法) | 第一个元素是条件 | 条件必须是单个表达式,嵌套多层建议改用 $switch |
| $ifNull | 值为 null 或缺失时取兜底值 | 只判断 null 与缺失,0 与空字符串不会触发 |
| $switch | 按 branches 顺序求值,命中即停 | 未命中且无 default 时字段不出现 |
| $divide 与 $cond 组合 | 先判断分母再计算 | 直接相除遇到 0 会报错中断整个管道 |
$switch 的分支按书写顺序求值:把最常见或最具体的条件放前面,既省计算也更符合预期;所有分支都不命中且未提供 default 时,该字段不会出现在结果文档里。
条件表达式不减少进入管道的文档数:需要过滤时仍需 $match,把过滤逻辑写成条件表达式只会增加计算量。