首页/数据/NoSQL 速查/$addFields / $set 添加计算字段
MongoDB99 条

$addFields / $set 添加计算字段

在保留原有字段的基础上新增或覆盖字段:$addFields 与 $set 等价($set 是 4.2 起的别名),随时可接其它阶段。

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

$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 白名单更不容易漏字段。

易错点

  • 以为 $addFields 会修改原文档:聚合只读,落库必须配 $merge、$out 或 updateOne
  • 把 $addFields 写在 $project 之后却引用已被剔除的字段,会得到 null 或直接报错
  • 对数组字段直接套标量操作符会报类型错误,需要先用 $map 或 $unwind 展开
  • 把能一步算完的表达式拆成连续多个 $addFields,管道变长且优化器更难合并阶段

数据来源与参考

  • MongoDB Manual: $addFields
​‌‌​​‌​​​‌‌​‌‌‌‌​‌‌​​​‌‌​‌‌‌​​‌‌​​‌​‌‌‌​​‌‌‌​​​‌​‌‌​‌​​‌​‌‌‌​​​‌​‌‌​‌​​‌​‌‌​​​‌‌​‌‌‌​‌​​​‌‌​‌‌‌‌​​‌​‌‌‌​​‌‌​​​‌‌​‌‌​‌‌‌‌​‌‌​‌‌​‌