MongoDB
 sql >> Base de Dados >  >> NoSQL >> MongoDB

Validação de documento aninhado do MongoDB para subdocumentos


Sim, você pode valide todos os subdocumentos em um documento negando $elemMatch , e você pode garantir que o tamanho não seja 1. Mas com certeza não é bonito! E não exatamente óbvio também.
> 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 }

Isso é confuso, mas funciona! O que isso significa é aceitar apenas documentos onde nem o tamanho de roles é 1 nem roles tem um elemento com um name que não é uma string ou um created_by que não é uma string .

Isso se baseia no fato de que, em termos lógicos,

É equivalente a

Temos que usar o último, pois o MongoDB apenas nos fornece um operador existente.

Prova


Documentos válidos funcionam:
> 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 })

Se um campo estiver faltando em roles , Falha:
> db.users.insert({
...   name: 'hello',
...   roles: [
...     {name: 'foo', created_by: '2222'},
...     {created_by: '3333'},
...   ]
... })
WriteResult({
    "nInserted" : 0,
    "writeError" : {
        "code" : 121,
        "errmsg" : "Document failed validation"
    }
})

Se um campo em roles tem o tipo errado, ele falha:
> 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"
    }
})

Se roles tem tamanho 1 ele falha:
> db.users.insert({
...   name: 'hello',
...   roles: [
...     {name: 'foo', created_by: '2222'},
...   ]
... })
WriteResult({
    "nInserted" : 0,
    "writeError" : {
        "code" : 121,
        "errmsg" : "Document failed validation"
    }
})

A única coisa que não consigo descobrir, infelizmente, é como garantir que as funções sejam uma matriz. roles: {$type: 'array'} parece falhar em tudo, presumo porque está realmente verificando se os elementos são do tipo 'array' ?