是的,就是你can通过否定来验证文档中的所有子文档$elemMatch
,并且你可以确保大小不为 1。但它肯定不漂亮!而且也不完全明显。
> db.createCollection('users', {
... validator: {
... name: {$type: 'string'},
... roles: {$exists: 'true'},
... $nor: [
... {roles: {$size: 1}},
... {roles: {$elemMatch: {
... $or: [
... {name: {$not: {$type: 'string'}}},
... {created_by: {$not: {$type: 'string'}}},
... ]
... }}}
... ],
... }
... })
{ "ok" : 1 }
这很令人困惑,但它确实有效!它的意思是只接受大小都不符合的文档roles
是 1 也不是roles
有一个元素带有name
那不是一个string
or a created_by
那不是一个string
.
这是基于这样一个事实:用逻辑术语来说,
对于所有 x:f(x) 和 g(x)
相当于
不存在 x s.t.:不存在 f(x) 或不存在 g(x)
我们必须使用后者,因为 MongoDB 只给我们一个存在操作符。
Proof
有效文件工作:
> db.users.insert({
... name: 'hello',
... roles: [],
... })
WriteResult({ "nInserted" : 1 })
> db.users.insert({
... name: 'hello',
... roles: [
... {name: 'foo', created_by: '2222'},
... {name: 'bar', created_by: '3333'},
... ]
... })
WriteResult({ "nInserted" : 1 })
如果缺少某个字段roles
, 它失败:
> db.users.insert({
... name: 'hello',
... roles: [
... {name: 'foo', created_by: '2222'},
... {created_by: '3333'},
... ]
... })
WriteResult({
"nInserted" : 0,
"writeError" : {
"code" : 121,
"errmsg" : "Document failed validation"
}
})
如果一个字段在roles
类型错误,失败:
> db.users.insert({
... name: 'hello',
... roles: [
... {name: 'foo', created_by: '2222'},
... {name: 'bar', created_by: 3333},
... ]
... })
WriteResult({
"nInserted" : 0,
"writeError" : {
"code" : 121,
"errmsg" : "Document failed validation"
}
})
If roles
大小为 1 时失败:
> db.users.insert({
... name: 'hello',
... roles: [
... {name: 'foo', created_by: '2222'},
... ]
... })
WriteResult({
"nInserted" : 0,
"writeError" : {
"code" : 121,
"errmsg" : "Document failed validation"
}
})
不幸的是,我唯一不明白的是如何确保角色是一个数组。roles: {$type: 'array'}
我认为似乎一切都失败了,因为它实际上是在检查元素的类型'array'
?