“Document failed validation”表明写入值与validator规则在BSON类型、字段存在性或嵌套结构上不匹配;MongoDB 5.0默认拒绝写入且错误详情需依赖驱动或shell版本支持,如bsonType:"int"要求显式使用NumberInt(25)或改用bsonType:["int","long","double"]兼容。

“Document failed validation”不是配置没生效,而是写入值和 validator 规则在 BSON 类型、字段存在性或嵌套结构上不匹配——MongoDB 5.0 会拒写,但默认不返回详细原因。
validator 规则里写的 "int" 和你插进去的 123 不是一回事
MongoDB 的 $jsonSchema 校验用的是 BSON 类型名,不是 JavaScript 或 JSON 的类型观。JSON 里没有 int,所有数字默认是 double;shell 或大多数驱动(如 PyMongo)插入 { age: 25 } 时,实际存的是 BSON double,哪怕你写了 bsonType: "int",它也会校验失败。
常见解决方式:
- 用
NumberInt(25)(shell)或Int32(25)(PyMongo)显式指定整型 - 把规则改成
bsonType: ["int", "long", "double"],接受常见数字子类型 - 改用
minimum/maximum配合bsonType: "number"("number"是 MongoDB 5.0+ 对数字类型的统称,兼容 int/long/double)
报错没详情?details 字段得靠驱动或 shell 版本支持
MongoDB 5.0 服务端确实在错误响应里加了 details 数组(含 operatorname、consideredvalue、reason),但很多旧版驱动(如 PyMongo WriteError: Document failed validation。
验证是否真有详情:
- 在 mongosh(v1.3+)中直接运行
db.students.insertOne({ year: "2025" }),错误里会带"details"字段 - Python 中用
try...except WriteError as e: print(e.details)——注意:PyMongo ≥ 4.2 才暴露e.details属性 - 如果仍为空,说明驱动未透传,此时只能靠日志:开启 MongoDB 日志级别为
2(mongod --logLevel 2),查Failed to validate document行
字段缺失却没报错?required 只管顶层,不递归检查嵌套
比如你写了 required: ["config"],但没写 config 里面的 timeout,那 { config: {} } 就能过;再比如 properties: { config: { bsonType: "object" } },却不声明 config 下的 required,里面空着也合法。
真正要兜住嵌套字段,必须展开写:
properties: {
config: {
bsonType: "object",
required: ["timeout", "retries"],
properties: {
timeout: { bsonType: "int", minimum: 1000 },
retries: { bsonType: "int", minimum: 0 }
}
}
}漏掉任何一层 required 或 properties,对应字段就等于“可选且无约束”。
更新操作绕过校验?不是绕过,是根本没触发
updateOne、findOneAndUpdate 等更新命令只有在修改了被 validator 约束的字段时才会触发校验;如果只改了个没在 schema 里定义的字段(比如加个 meta.updatedAt),哪怕整个文档现在不符合 schema,MongoDB 也不拦——它只校验本次变更后“新值”是否合规,不重验全量文档。
这意味着:
- 已有脏数据不会被自动清理,
validationLevel: "strict"(默认)只管新写入/修改部分 - 想扫出历史不合规文档,得手动跑:
db.collection.find({ $nor: [ /* your jsonSchema conditions */ ] }) - 慎用
validationLevel: "moderate":它允许 update 时不校验未修改字段,但会让数据一致性更难追踪
最易被忽略的一点:validator 是写前拦截器,不是读时过滤器;它不改变查询行为,也不影响索引效率——但它一旦配错,就会让合法业务请求静默失败,而错误信息又藏得深。上线前务必用真实数据 + 真实驱动复现校验路径,别只在 shell 里测。

















