$cond适用于二选一场景,语法轻量但嵌套易错;$switch适合多分支判断,结构清晰且顺序执行,二者均须显式指定else/default,否则报错。

直接说结论:$cond 适合二选一(if-else),$switch 更接近 SQL 的 CASE WHEN 多分支结构,但两者都**不能省略 else/default**,否则会报错或返回 null。
什么时候该用 $cond 而不是 $switch
$cond 是最轻量的条件表达式,适用于字段值只有两种状态的场景,比如“是否已支付”“是否启用”“数量是否达标”。它语法紧凑,嵌套也直观,但写三层以上就容易晕。
- 推荐用对象形式:
{$cond: {if: {$gte: ["$qty", 250]}, then: 30, else: 20}},可读性比数组形式高 - 数组形式
{$cond: [{$eq: ["$status", "active"]}, "online", "offline"]}看似短,但一旦中间加个逻辑运算(比如{$and: [...]}),括号嵌套极易出错 - 注意:所有三个参数必须存在,
else: null或else: ""都得显式写出来,MongoDB 不接受缺省 - 常见错误是把字符串字面量写成未加引号的变量名,比如
else: $unknown(实际应为else: "$unknown"或else: null)
多分支判断优先选 $switch,但 default 不可省
$switch 的设计目标就是替代嵌套 $cond,尤其当你要处理 status 字段的 "pending" / "processing" / "shipped" / "cancelled" 四种情况时。它的分支顺序敏感,只执行第一个匹配的 case,这点和 SQL 的 CASE WHEN 完全一致。
- 每个
branches项必须且仅含case和then字段,多一个字段(比如不小心加了注释字段)就会报错 -
default是可选的,但生产环境强烈建议加上,否则遇到没覆盖到的值(比如新上线的"refunding"状态),整个 pipeline 会中断并抛出undefined path类错误 - 示例中容易漏掉
case表达式的布尔转换逻辑:比如{$case: "$status"}实际等价于{$case: {$ne: ["$status", null]}},空字符串、0、false都会被转成false—— 所以更安全的是显式比较:{$case: {$eq: ["$status", "shipped"]}}
$cond 嵌套写法与可维护性陷阱
当只有 MongoDB 4.2 以下版本可用、不支持 $switch 时,$cond 嵌套是唯一选择。但它极易变成“右漂移代码”,越嵌越难调试。
- 典型嵌套结构:
{$cond: {if: A, then: X, else: {$cond: {if: B, then: Y, else: Z}}}},注意第二层$cond必须完整包裹在else里,不能漏大括号 - 嵌套超过两层后,建议拆成
$project步骤先计算中间字段(如status_category),再用单层$cond处理,避免一行写 200 字符 - 调试时可临时把
then/else替换为固定字符串(如"hit-A"、"hit-B"),确认逻辑路径是否按预期走 - 聚合阶段中若在
$group里用嵌套$cond,要注意字段引用是否在当前作用域内——比如$sum内部不能直接访问上一级$project新增的字段
真实聚合场景下的性能与兼容性提醒
无论用 $cond 还是 $switch,它们都在内存中逐文档计算,对大数据集影响不大;真正拖慢速度的是前面的 $match 是否能命中索引。
-
$switch从 MongoDB 3.4 引入,低于此版本只能用$cond嵌套 - 如果字段可能为
null或缺失,{$eq: ["$field", "value"]}会返回false,但{$in: ["$field", ["value"]]}在字段缺失时也返回false—— 更鲁棒的做法是先用{$and: [{$ne: ["$field", null]}, {$ne: ["$field", ""]}]}排除无效值 - 在
$addFields或$set中使用时,不要试图复用同名字段做条件判断(如先$set: {score: {$cond: [...]}},再基于这个score做下一轮判断),MongoDB 不保证字段计算顺序,应分步写
最常被忽略的一点:所有条件表达式里的字段路径(如 "$qty")必须带引号,且是双引号;单引号或不带引号在 shell 里可能侥幸通过,但在 driver(如 Node.js 的 mongodb package)中必然解析失败。


















