JSON Schema在MongoDB中是集合级强制数据契约,插入或更新时自动校验并拒绝不合规文档,具有服务端原子性、不可绕过性,仅对新写操作生效,不追溯旧数据。

什么是 jsonSchema 在 MongoDB 中的实际作用
它不是校验工具,而是集合级别的数据契约。MongoDB 会在插入或更新文档时自动按 schema 检查结构,不满足就直接拒绝写入,并返回 Document failed validation 错误。这和应用层手动校验有本质区别:schema 是服务端强制的、原子的、不可绕过的约束。
注意:只对 insertOne、insertMany、updateOne(含 upsert: true)等写操作生效;对已有旧文档不做 retroactive 校验,除非你显式触发重写(比如 replaceOne)。
如何给集合添加 jsonSchema 校验规则
必须通过 collMod 命令或创建集合时指定,不能事后用 createIndex 或其它方式“追加”。推荐在集合初建时一次性设好:
db.createCollection("users", {
validator: {
$jsonSchema: {
bsonType: "object",
required: ["name", "email"],
properties: {
name: { bsonType: "string", maxLength: 50 },
email: { bsonType: "string", pattern: "^.+@.+$" },
age: { bsonType: "int", minimum: 0, maximum: 150 }
}
}
}
})
常见错误:
- 漏写外层
$jsonSchema字段 —— 直接写validator: { bsonType: "object" }会静默失效 - 在已有集合上用
createCollection覆盖 —— 实际不会修改,需用runCommand({ collMod: ..., validator: ... }) - 把正则写成 JavaScript 字面量(
/^.+@.+$/)—— 必须是字符串形式的pattern
jsonSchema 中哪些字段类型和校验最常用也最容易踩坑
MongoDB 的 bsonType 和 JSON Schema 标准不完全一致,例如没有 number,只有 double、int、long、decimal 等具体类型。混用会导致意外放行或拦截:
-
bsonType: "int" 只接受 32 位整数,42.0 或 NumberLong("42") 都会失败
-
bsonType: "string" 不校验是否为空字符串,需额外加 minLength: 1
-
required 只检查字段是否存在,不检查是否为 null;要禁止 null,得配合 enum: [{ $ne: null }] 或用 not: { type: "null" }
- 嵌套对象用
properties + required,但数组内元素校验要用 items,不是 property
更新 schema 时要注意什么
MongoDB 允许随时修改 validator,但新规则**立即生效**,且不区分“开发/生产”环境。一次宽松 → 严格变更可能批量阻断写入:
- 先用
db.runCommand({ collStats: "users" }) 查看当前文档数量,评估影响面
- 若要新增必填字段,可先设
required: [] + default(注意:MongoDB 不支持 default 关键字,得靠应用层或 $setOnInsert 补)
- 测试时用
updateOne({ _id: ObjectId("...") }, { $set: { newField: "test" } }) 触发校验,比 insert 更安全
- 线上变更建议搭配
validationLevel: "warn"(仅记录日志不报错),验证无误后再切到 "strict"
实际约束力取决于你是否启用 validationAction: "error",默认就是 error;但如果集合早期没设 validator,后来加了,那些历史文档仍可读可查——只是再也改不了、删不了、也 insert 不进去任何不合规的新数据。这点常被忽略。
bsonType: "int" 只接受 32 位整数,42.0 或 NumberLong("42") 都会失败bsonType: "string" 不校验是否为空字符串,需额外加 minLength: 1
required 只检查字段是否存在,不检查是否为 null;要禁止 null,得配合 enum: [{ $ne: null }] 或用 not: { type: "null" }
properties + required,但数组内元素校验要用 items,不是 property
- 先用
db.runCommand({ collStats: "users" })查看当前文档数量,评估影响面 - 若要新增必填字段,可先设
required: []+default(注意:MongoDB 不支持default关键字,得靠应用层或$setOnInsert补) - 测试时用
updateOne({ _id: ObjectId("...") }, { $set: { newField: "test" } })触发校验,比 insert 更安全 - 线上变更建议搭配
validationLevel: "warn"(仅记录日志不报错),验证无误后再切到"strict"
validationAction: "error",默认就是 error;但如果集合早期没设 validator,后来加了,那些历史文档仍可读可查——只是再也改不了、删不了、也 insert 不进去任何不合规的新数据。这点常被忽略。











