$addFields 是什么
$addFields 在聚合管道里为文档新增或覆盖字段,其余原有字段全部保留。表达式可以是常量、字段引用($name)、算术、条件与数组操作;$set 从 4.2 起作为同义词使用,行为完全一致。它和 $project 的差别是定位不同:$project 是白名单,只输出显式列出的字段;$addFields 是增量叠加,适合在管道中段补算派生值,后续阶段既能用新字段也能继续用老字段。
基本信息
| 语法 | { $addFields: { 新字段名: 表达式 } } |
|---|---|
| 别名 | $set 语义完全相同(4.2 起提供) |
| 阶段位置 | 可出现在管道任意位置,只在后续阶段生效 |
| 字段引用 | "$name" 引用字段,嵌套用 "$a.b" |
| 持久化 | 只影响本条聚合结果,不写回集合 |
典型使用场景
- 派生指标:单价乘数量得到金额,供后续排序与筛选使用
- 条件打标:用 $cond 按阈值给文档打上 bulk / retail 之类标签
- 单位换算:把毫秒或字节换算成更易读的单位再输出
- 拼接展示字段:把多个字段拼成前端直接可用的展示串
- 空值兜底:对缺失字段用 $ifNull 补默认值,省去下游大量判空
组合写法示例
组合写法示例
db.orders.aggregate([
{ $addFields: {
total: { $multiply: ["$qty", "$price"] }, // 派生金额
level: { $cond: [{ $gte: ["$qty", 10] }, "bulk", "retail"] }, // 条件打标
label: { $concat: ["$", { $toString: "$qty" }] } // 拼展示串
} },
{ $match: { level: "bulk" } }, // 后续阶段可直接引用新字段
{ $sort: { total: -1 } }
])常用表达式速查
| 操作符 | 用途 | 写法要点 |
|---|---|---|
| $multiply | 数值相乘 | { $multiply: ["$qty", "$price"] } |
| $cond | 条件分支 | { $cond: [条件, 真值, 假值] } |
| $ifNull | 空值兜底 | { $ifNull: ["$a", 0] } |
| $concat | 字符串拼接 | 两边必须都是字符串,需要 $toString |
| $size | 数组长度 | { $size: "$tags" } |
$addFields 算出的字段只在这次聚合结果里存在,要落库得接 $merge 或 $out,或者改用 updateMany 写回。
字段名里带点号会被解释成嵌套路径,"a.b" 相当于在 a 对象里加 b;确实需要点号作为键名时得改成 $setField 一类写法。
同一阶段内新增的多个字段不能互相引用:想用刚算出的 A 去算 B,必须拆成两步 $addFields,先后顺序就是字段可见顺序。
管道里删字段用 $unset(4.2 起提供),它和 $addFields 正好相反;想既加又减时用 $unset 比写 $project 白名单更不容易漏字段。