Mongoose的default仅在字段为undefined时生效,传null或空字符串会跳过;required与default机制独立;需在数据入库前清洗无效值以确保default触发。

默认值只在字段完全缺失时生效,传入 null 或空字符串会跳过 default
这是最常被忽略的前提:Mongoose 的 default 函数或值,仅在文档中**根本没有该字段**(undefined)时才触发。一旦你显式传了 null、'' 或 0,Mongoose 就认为“你有意设置了这个值”,直接跳过 default 逻辑。
- 表单提交空字符串
''→ 不触发default,哪怕字段类型是String - 前端传
{ price: null }→ 后端收到的是null,不是undefined,default被绕过 -
new User({ name: 'Alice', age: null }).save()→age字段存为null,不会变成default: 18
mongoose 的 required 和 default 是两套机制,不能互相替代
required: true 控制校验阶段是否报错;default 控制字段缺失时的填充行为。两者不联动。比如:
-
price: { type: Number, default: 0 }→ 插入{}时存0;插入{ price: null }时存null -
price: { type: Number, required: true, default: 0 }→ 插入{}仍存0;但插入{ price: null }会校验失败(因为null不满足required)
如何让空输入真正走 default
关键是在数据进 Mongoose 之前,把无效值(null、''、undefined)清理掉,而不是依赖 schema 层自动兜底:
- 用中间件预处理:在
save前检查字段,if (this.price == null || this.price === '') delete this.price - 用
pre('validate')钩子统一归一化:if (this.name === '') this.name = undefined - 前端传参时避免发
null:用Object.fromEntries(Object.entries(data).filter(([, v]) => v != null))过滤
strict: true 是默认行为,它会让 find() 静默丢弃未定义字段,但不影响 default 生效时机
注意别混淆两个问题:default 失效是写入时的逻辑;而 strict: true 影响的是读取时是否返回字段。即使你加了 default: 'pending',如果查询时用了 Model.find().lean() 或 { strict: false },也不会改变 default 是否被触发——它只发生在 save() 或 create() 阶段。
真正容易踩的坑,是以为「只要字段没填,就一定会走 default」,结果发现数据库里存了一堆 null。根源往往不在 schema 写法,而在上游数据没做清洗。











