模式验证
版本 3.2 中的新增功能。
MongoDB 提供在更新和插入期间执行模式验证的功能。
您可以为 MongoDB Atlas 中托管的部署在用户界面中实施模式验证。
指定验证规则
验证规则基于每个集合。
要在创建新集合时指定验证规则,请使用带有validator
选项的 db.createCollection()
。
要向现有集合添加文档验证,请使用带有validator
选项的collMod
命令。
MongoDB 还提供了以下相关选项:
validationLevel
选项,用于确定 MongoDB 在更新期间将验证规则应用于现有文档的严格程度。validationAction
选项,它决定 MongoDB 是应error
并拒绝违反验证规则的文档,还是应warn
记录日志中的违规情况但允许无效文档。
JSON schema
版本 3.6 中的新增功能。
从版本3.6开始, MongoDB 支持 JSON schema 验证。 要指定 JSON schema 验证,请在validator
表达式中使用$jsonSchema
操作符。
注意
JSON schema 是执行模式验证的推荐方法。
例如,以下示例使用 JSON schema指定验证规则:
db.createCollection("students", { validator: { $jsonSchema: { bsonType: "object", required: [ "name", "year", "major", "address" ], properties: { name: { bsonType: "string", description: "must be a string and is required" }, year: { bsonType: "int", minimum: 2017, maximum: 3017, description: "must be an integer in [ 2017, 3017 ] and is required" }, major: { enum: [ "Math", "English", "Computer Science", "History", null ], description: "can only be one of the enum values and is required" }, gpa: { bsonType: [ "double" ], description: "must be a double if the field exists" }, address: { bsonType: "object", required: [ "city" ], properties: { street: { bsonType: "string", description: "must be a string if the field exists" }, city: { bsonType: "string", description: "must be a string and is required" } } } } } } })
有关更多信息,请参阅 $jsonSchema
。
bsonType
定义可以在BSON types页面上找到。
其他查询表达式
除了使用$jsonSchema
查询操作符的 JSON schema 验证之外,MongoDB 还支持使用其他查询操作符进行验证,但以下情况除外:
例如,以下示例使用查询表达式指定验证器规则:
db.createCollection( "contacts", { validator: { $or: [ { phone: { $type: "string" } }, { email: { $regex: /@mongodb\.com$/ } }, { status: { $in: [ "Unknown", "Incomplete" ] } } ] } } )
行为
在更新和插入期间进行验证。 向集合添加验证时,现有文档在修改之前不会进行验证检查。
要对现有文档执行验证检查,请使用validate
命令或db.collection.validate()
shell助手。
现有文档
validationLevel
选项确定 MongoDB 对哪些操作应用验证规则:
如果
validationLevel
为strict
(默认值),MongoDB 将验证规则应用于所有插入和更新。如果
validationLevel
为moderate
,MongoDB 将验证规则应用于已满足验证条件的现有文档的插入和更新。 对于moderate
级别,不检查对不满足验证条件的现有文档的更新的有效性。
例如,使用以下文档创建 contacts
集合:
db.contacts.insert([ { "_id": 1, "name": "Anne", "phone": "+1 555 123 456", "city": "London", "status": "Complete" }, { "_id": 2, "name": "Ivan", "city": "Vancouver" } ])
发出以下命令,将验证器添加到contacts
集合中:
db.runCommand( { collMod: "contacts", validator: { $jsonSchema: { bsonType: "object", required: [ "phone", "name" ], properties: { phone: { bsonType: "string", description: "must be a string and is required" }, name: { bsonType: "string", description: "must be a string and is required" } } } }, validationLevel: "moderate" } )
contacts
集合现在有一个验证级别为moderate
的验证器:
如果您尝试使用
_id: 1
更新文档,MongoDB 将应用新的验证规则,因为现有文档符合条件。相反,MongoDB 不会将验证规则应用于对包含
_id: 2
的文档的更新,因为它不符合验证规则。
从 MongoDB 5.0版本开始,验证器会在不满足验证条件时返回详细的错误信息。 错误输出非常详尽 — 会报告所有错误,而不仅仅是第一个错误。
重要
错误输出供人类使用。它将来可能会更改,不应在脚本中依赖它。
在下一个示例中,这两个更新都与我们上面创建的验证规则不一致,该规则要求 name
是string 。
db.contacts.update( { _id: 1 }, { $set: { name: 10 } } ) db.contacts.update( { _id: 2 }, { $set: { name: 20 } } )
以下输出显示带有_id: 1
的文档未通过验证,并附有详细解释,如errInfo
对象所示。 包含_id: 2
的文档更新成功,因为该文档在添加验证时不符合初始条件。
// _id: 1 WriteResult({ "nMatched" : 0, "nUpserted" : 0, "nModified" : 0, "writeError" : { "code" : 121, "errmsg" : "Document failed validation", "errInfo" : { "failingDocumentId" : 1, "details" : { "operatorName" : "$jsonSchema", "schemaRulesNotSatisfied" : [ { "operatorName" : "properties", "propertiesNotSatisfied" : [ { "propertyName" : "name", "details" : [ { "operatorName" : "bsonType", "specifiedAs" : { "bsonType" : "string" }, "reason" : "type did not match", "consideredValue" : 10, "consideredType" : "double" } ] } ] } ] } } } }) // _id: 2 WriteResult({ "nMatched" : 1, "nUpserted" : 0, "nModified" : 1 })
要完全禁用验证,可以将validationLevel
设置为off
。
接受或拒绝无效文档
validationAction
选项确定 MongoDB 如何处理违反验证规则的文档:
如果
validationAction
为error
(默认值),MongoDB 将拒绝任何违反验证条件的插入或更新。如果
validationAction
为warn
,MongoDB 会记录所有违规,但允许继续进行插入或更新。
例如,使用以下 JSON schema 验证器创建contacts2
集合:
db.createCollection( "contacts2", { validator: { $jsonSchema: { bsonType: "object", required: [ "phone" ], properties: { phone: { bsonType: "string", description: "must be a string and is required" }, email: { bsonType : "string", pattern : "@mongodb\.com$", description: "must be a string and match the regular expression pattern" }, status: { enum: [ "Unknown", "Incomplete" ], description: "can only be one of the enum values" } } } }, validationAction: "warn" } )
通过warn
validationAction
,MongoDB 会记录任何违规行为,但允许继续进行插入或更新。
例如,以下插入操作违反了验证规则:
db.contacts2.insertOne( { name: "Amanda", status: "Updated" } )
但是,由于validationAction
只是warn
,MongoDB 仅记录验证违规消息并允许操作继续。 运行以下命令,查看 MongoDB 日志:
db.adminCommand( { getLog: "global" } )
根据集合使用情况,此命令可能会返回大量数据。 验证错误(日志中的一长行,为便于阅读而在此处重新格式化)包含如下信息:
"{\"t\":{\"$date\":\"2021-01-20T15:59:57.305+00:00\"}, \"s\":\"W\", \"c\":\"STORAGE\", \"id\":20294, \"ctx\":\"conn1\", \"msg\":\"Document would fail validation\", \"attr\":{\"namespace\":\"test.contacts2\", \"document\":{\"_id\":{\"$oid\":\"6008537d42e0d23385568881\"}, \"name\":\"Amanda\", \"status\":\"Updated\"}, \"errInfo\":{\"failingDocumentId\":{\"$oid\":\"6008537d42e0d23385568881\"}, \"details\":{\"operatorName\":\"$jsonSchema\", \"schemaRulesNotSatisfied\":[ {\"operatorName\":\"properties\", \"propertiesNotSatisfied\":[ {\"propertyName\":\"status\", \"details\":[ {\"operatorName\":\"enum\", \"specifiedAs\":{\"enum\":[ \"Unknown\", \"Incomplete\"]}, \"reason\":\"value was not found in enum\", \"consideredValue\":\"Updated\"}]}]}, {\"operatorName\":\"required\", \"specifiedAs\":{\"required\":[\"phone\"]}, \"missingProperties\":[\"phone\"]}]}}}}"
限制
不能为 admin
、local
和 config
数据库中的集合指定验证器。
无法为 system.*
集合指定验证器。
bypassDocumentValidation
用户可以使用bypassDocumentValidation
选项绕过文档验证。
以下命令可以使用新选项bypassDocumentValidation
绕过每个操作的验证:
对于启用了访问控制的部署,要绕过文档验证,经过身份验证的用户必须有 bypassDocumentValidation
动作。内置角色 dbAdmin
和 restore
可执行此动作。