$convert 的 onError 和 onNull 是防止聚合崩溃的关键参数:onError 处理转换失败(如字符串转日期异常),onNull 仅响应字段为 null 或缺失;二者须显式设置且严格驼峰命名,不可拼错或混用。

聚合阶段中 $convert 的 onError 和 onNull 到底怎么填
这两个参数不是可选的“锦上添花”,而是防止聚合中途崩溃的关键开关。MongoDB 在 $convert 遇到无法解析的值(比如把 "abc" 转成 int)时,默认直接报错终止整个管道,而不是跳过或设为 null。
-
onError用于捕获类型转换失败(如"2024-02-xx"转Date失败),必须是字面量或表达式,不能是函数名或变量名;常见填null、0、"invalid"或$$REMOVE -
onNull仅在输入字段本身为null或缺失时触发,和onError互不干扰;若想统一处理空值和错误,得两个都显式设成一样 - 别写
onError: "ignore"—— MongoDB 不认这个字符串,会报"unknown operator: onError"类似错误
$convert 在 $group 里失效?其实是作用域搞错了
很多人把 $convert 塞进 $group 的 $sum 或 $avg 里,结果发现 onError 完全没生效。根本原因是:这些累加器内部不支持嵌套表达式里的错误处理机制,$convert 被提前求值,错误直接抛出。
- 正确做法是把
$convert放在$group之前,用$set或$addFields先规整好字段类型 - 如果必须在
$group内部做转换,只能用$cond+$isNumber/$type手动判断,再决定取值,绕过$convert - 注意
$convert对 ObjectId、Binary 等特殊类型支持有限,转string没问题,但转int会失败且onError未必兜得住
Node.js 驱动里传参写错格式,错误信息根本不提示 onError
MongoDB Shell 里写 { onError: null } 没问题,但 Node.js 驱动(尤其是 v4+)如果用 JavaScript 对象字面量传入聚合阶段,容易因键名大小写或嵌套层级出错,导致 onError 被忽略,错误照常抛出。
- 确保写法是
{ $convert: { input: "$price", to: "int", onError: null, onNull: null } },不是on_error或onerror - 用 TypeScript 或 IDE 插件校验字段名,
onError和onNull是严格驼峰,拼错一个字母就静默失效 - 驱动日志级别设为
debug时,能看到实际发送的 BSON,确认这两个键是否真的进了请求体 —— 很多时候是 JS 对象被序列化时丢掉了
为什么 onNull: "$$REMOVE" 有时让字段消失,有时又留个 null
这取决于字段“空”的来源:$$REMOVE 只在当前文档上下文中移除字段,但如果上游已经把字段设为 null(比如 $ifNull 返回了 null),那 $convert 的 onNull 就不会触发 —— 因为输入是 null 值,不是“缺失”。
-
onNull只响应 undefined / 字段不存在 / 显式null(需配合$literal: null等) -
$$REMOVE在$project或$addFields中有效,在$group的push里无效,后者会把$$REMOVE当普通值塞进数组 - 真正想“彻底删字段”,得用
$unset阶段,别指望onNull代劳









