mongodb默认不校验文档结构,需显式配置$jsonschema验证器并设validationaction为"error"才能拦截无效数据;它作为createcollection或collmod命令中的嵌套json schema对象,在插入/更新时触发,对历史数据无影响。

MongoDB 本身不默认校验文档结构,无效数据能直接写入——必须显式启用 $jsonSchema 验证器,并配好 validationAction 才能真正拦截。
如何用 $jsonSchema 定义强制字段与类型约束
验证器不是“开关”,而是嵌套在 createCollection 或 collMod 命令里的 JSON Schema 对象。它只在插入/更新时触发,对已有数据无影响。
常见误操作是把 required 字段写错层级,或漏掉 bsonType 导致类型宽松(比如字符串能塞进数字字段):
-
required必须是顶层数组,列出字段名字符串,如["phone", "email"] - 每个
properties下的字段必须声明bsonType,"string"和"int"不可互换 - 正则校验用
pattern,注意转义:邮箱结尾@mongodb\.com$中的点要加反斜杠 - 数值范围用
minimum/maximum,不是min/max
示例(创建带强约束的集合):
db.createCollection("users", {
validator: {
$jsonSchema: {
bsonType: "object",
required: ["username", "age"],
properties: {
username: { bsonType: "string", minLength: 3 },
age: { bsonType: "int", minimum: 0, maximum: 120 }
}
}
},
validationAction: "error"
})
validationAction: "error" 与 "warn" 的实际区别
选 "error" 时,违反任一规则都会让整个 insertOne 或 updateOne 操作失败,并抛出 MongoServerError: Document failed validation;选 "warn" 则写入成功,只在 MongoDB 日志里记一条警告,应用层完全感知不到。
这导致两个关键事实:
- 前端或业务代码绝不能依赖
"warn"做数据清洗——它不返回错误,也不修改文档 -
"error"是唯一能保证下游服务拿到的数据符合 Schema 的方式,但要求你提前处理好迁移历史数据(否则老文档会卡住所有写入) - 副本集或分片集群中,
validationAction设置必须一致,否则主从行为可能分裂
为什么 insertMany 有时只报错部分文档?
因为 MongoDB 默认开启 ordered: true。一旦某个文档校验失败,后续文档全部跳过——看起来像“批量失败”,其实是“遇到第一个错就停”。
想让合法文档继续写入,需显式传 { ordered: false }:
db.users.insertMany([
{ username: "a", age: 25 }, // ❌ username 太短
{ username: "bob", age: 30 } // ✅ 会被写入
], { ordered: false })
但要注意:ordered: false 不改变单文档校验逻辑,只是让错误不中断队列;且返回结果里 writeErrors 数组会包含具体哪个索引、哪条规则失败,需手动解析。
验证器无法覆盖的边界情况
$jsonSchema 解决不了三类问题:
- 跨字段逻辑(如 “start_date 必须早于 end_date”),JSON Schema 标准不支持字段间引用
- 动态值校验(如 “email 域名必须存在于白名单表中”),需要靠应用层或聚合管道预检
- 大字段内容语义(如 “description 不能含敏感词”),得靠外部 NLP 服务或正则扫描
这些场景下,验证器只能做基础守门员,真正的数据洁癖还得靠应用层 try/catch 捕获 MongoServerError 并做 fallback 处理——比如降级写入到 invalid_users 归档集合,而不是直接丢弃。











