MongoDB 基础系列九:数据建模之文档验证 Document Validation

前言

此篇博文是 Mongdb 基础系列之一;主要介绍 MongoDB 的数据建模相关内容;

本文为作者的原创作品,转载需注明出处;

简介

Document Validation 是 3.2 以后加入的内容,

MongoDB provides the capability to validate documents during updates and insertions. Validation rules are specified on a per-collection basis using the validator option, which takes a document that specifies the validation rules or expressions. Specify the expressions using any query operators, with the exception of $near, $nearSphere, $text, and $where.

MongoDB 提供了对文档进行更新插入的验证规则;一个验证规则是作用在一个 collection 上;验证规则是通过 validator 选项进行创建的,它将会为每一个文档创建相关的 validation rules expressions (验证规则表达式);可以使用任何的 query operators 来定义此验证规则表达式,但是除了 $near, $nearSphere, $text, and $where 以外;

另外注意两个非常重要的 options,既 validationLevel optionvalidationAction optionvalidationLevel option 将会控制如何对已经存在的 documents 进行验证;validationAction option

如何添加验证规则

对已经存在的 collection 添加验证规则

对已经存在的 collection,使用命令 collMod 来为其创建验证规则;比如,

1
2
3
4
5
db.runCommand( {
collMod: "contacts",
validator: { $or: [ { phone: { $exists: true } }, { email: { $exists: true } } ] },
validationLevel: "moderate"
} )

上述命令既是对已经存在的 contacts collection 添加验证规则;

在新建的 collection 的时候添加验证规则

如果是新建 collection,可以使用 db.createCollection() 命令为其创建验证规则,就像下面这样,

1
2
3
4
5
6
7
8
9
db.createCollection( "contacts",
{ validator: { $or:
[
{ phone: { $type: "string" } },
{ email: { $regex: /@mongodb\.com$/ } },
{ status: { $in: [ "Unknown", "Incomplete" ] } }
]
}
} )

可见,在创建 collection 的时候,指定可选项 validator 即可为其创建验证规则;

重要的 Options

validationLevel option

validationLevel 选项表示如何对已经存在的 documents 进行验证;默认是strict,表示对所有已经存在的 documents 均要进行验证;可以将其设置为moderate,表示如果文档中的字段匹配了验证规则中所定义的字段,才进行验证,若是没有匹配,则不验证;看下面这个例子,

假设我们有 contacts 这样一个 collection,包含两个 documents,

1
2
3
4
5
6
7
8
9
10
11
12
{
"_id": "125876",
"name": "Anne",
"phone": "+1 555 123 456",
"city": "London",
"status": "Complete"
},
{
"_id": "860000",
"name": "Ivan",
"city": "Vancouver"
}

注意,这两个 document 的字段并不相同,第二个 document 只有第一个 document 字段的一部分;我们为该 collection 添加 validation rules,如下,

1
2
3
4
5
db.runCommand( {
collMod: "contacts",
validator: { $or: [ { phone: { $exists: true } }, { email: { $exists: true } } ] },
validationLevel: "moderate"
} )

这里我们将 validationLevel 设置为moderate,如果你对 _id: 125876 进行更新操作,则验证规则将会作用到该 document 上;但是如果你对 _id: 860000 进行更新操作,验证规则将不会作用到该 document 上;

如果你想要彻底的禁用验证功能,则将 validationLevel 设置为off即可;

validationAction option

validationAction option 决定了如何对违反了验证规则的 documents 进行处理;

默认情况下,validationAction 的默认值是error,表示在 insertion 或者是 udpate documents 的时候,拒绝任何违反了验证规则的 documents;如果将 validationAction 的设置为warn,它只在日志中通过警告的方式记录这些违规操作,但是仍然会插入或更新这些 documents;

看下面这个例子,

1
2
3
4
5
6
7
8
9
10
11
12
db.createCollection( "contacts",
{
validator: { $or:
[
{ phone: { $type: "string" } },
{ email: { $regex: /@mongodb\.com$/ } },
{ status: { $in: [ "Unknown", "Incomplete" ] } }
]
},
validationAction: "warn"
}
)

如上所述,我们对 contacts collection 的三个字段分别定义了三个不同的验证规则,并且将 validationAction 设置为warn;然后我们写入一个非法的 documents,

1
db.contacts.insert( { name: "Amanda", status: "Updated" } )

很明显,该 document 的 status 字段不合法,该字段只允许两种状态既 UnknownIncomplete;但是,因为这里的级别是warn,所以它仍然可以插入成功,但是日志中会包含该警告日志,如下

1
2015-10-15T11:20:44.260-0400 W STORAGE  [conn3] Document would fail validation collection: example.contacts doc: { _id: ObjectId('561fc44c067a5d85b96274e4'), name: "Amanda", status: "Updated" }

一些重要的限制

You cannot specify a validator for collections in the admin, local, and config databases.

You cannot specify a validator for system. collections.

绕开文档验证

用户可以通过使用 bypassDocumentValidation 选项来绕开文档验证;这些命令可以支持 bypassDocumentValidation 选项;

For deployments that have enabled access control, to bypass document validation, the authenticated user must have bypassDocumentValidation action. The built-in roles dbAdmin and restore provide this action.

针对已经启动访问控制的部署实例,要想绕开文档验证,具有权限的用户必须拥有 bypassDocumentValidation 的权限;内置的 dbAdminrestore 默认拥有此权限;

References

https://docs.mongodb.com/manual/core/document-validation/