Explore o novo chatbot do Developer Center! O MongoDB AI chatbot pode ser acessado na parte superior da sua navegação para responder a todas as suas perguntas sobre o MongoDB .

Junte-se a nós no Amazon Web Services re:Invent 2024! Saiba como usar o MongoDB para casos de uso de AI .
Desenvolvedor do MongoDB
Central de desenvolvedor do MongoDBchevron-right
Produtoschevron-right
MongoDBchevron-right

Mensagens de erro aprimoradas para validação de esquema no MongoDB 5.0

Katya Kamenieva10 min read • Published Jan 10, 2022 • Updated Jun 14, 2023
MongoDBEsquema
Ícone do FacebookÍcone do Twitterícone do linkedin
Avalie esse anúncio
star-empty
star-empty
star-empty
star-empty
star-empty

Intro

Muitos MongoDB dependem da validação de esquema para impor as regras que regem a estrutura e a integridade dos documentos em suas collection. Mas um dos desafios que eles enfrentaram foi entender rapidamente por que um documento que não correspondia ao esquema não podia ser inserido ou atualizado. Isso mudará no próximo MongoDB 5.0 versão.
A facilidade de uso da validação do esquema será significativamente melhorada com a geração de mensagens de erro descritivas sempre que uma operação falhar na validação. Essas informações adicionais fornecem uma visão valiosa sobre quais partes de um documento em uma operação de inserção/atualização falharam na validação em relação a quais partes do validador de uma collection e como. A partir dessas informações, você pode identificar e corrigir rapidamente erros de código que estão fazendo com que os documentos não estejam em conformidade com suas regras de validação. Chega de depuração tediosa cortando seu documento em pedaços para isolar o problema!
Se você quiser avaliar esse recurso e nos fornecer um feedback antecipado, preencha este formulário para participar do programa de pré-visualização.
A maneira mais popular de Express as regras de validação é JSON schema. É um padrão amplamente aceito que também é usado na especificação e validação da REST API. E no MongoDB, você pode combinar o JSON schema com a linguagem de query do MongoDB (MQL) para fazer ainda mais.
Nesta publicação, gostaria de revisar alguns exemplos para reiterar os recursos da validação de esquema e mostrar a adição de novas mensagens de erro detalhadas.

Como são as novas mensagens de erro?

Primeiro, vamos dar uma olhada na nova mensagem de erro. É uma mensagem estruturada no formato BSON, explicando qual parte do documento não correspondeu às regras e qual regra de validação causou isso.
Considere este validador básico que garante que o campo de preço não aceite valores negativos. No JSON schema, a propriedade é equivalente ao que chamamos de "campo" no MongoDB.
1{
2 "$jsonSchema": {
3 "properties": {
4 "price": {
5 "minimum": 0
6 }
7 }
8 }
9}
Ao tentar inserir um documento com {price: -2}, a seguinte mensagem de erro será retornada.
1{
2 "code": 121,
3 "errmsg": "Document failed validation",
4 "errInfo": {
5 "failingDocumentId": ObjectId("5fe0eb9642c10f01eeca66a9"),
6 "details": {
7 "operatorName": "$jsonSchema",
8 "schemaRulesNotSatisfied": [
9 {
10 "operatorName": "properties",
11 "propertiesNotSatisfied": [
12 {
13 "propertyName": "price",
14 "details": [
15 {
16 "operatorName": "minimum",
17 "specifiedAs": {
18 "minimum": 0
19 },
20 "reason": "comparison failed",
21 "consideredValue": -2
22 }
23 ]
24 }
25 ]
26 }
27 ]
28 }
29 }
30}
Alguns dos campos principais da resposta são:
  • failingDocumentId - o _id do documento que foi avaliado
  • operatorName - o operador usado na regra de validação
  • propertiesNotSatisfied - a lista de campos (properties) que falharam nas verificações de validação
  • propertyName - o campo do documento que foi avaliado
  • specifiedAs - a regra como foi expressa no validador
  • reason - explanation de como a regra não foi satisfeita
  • consideredValue - valor do campo no documento que foi avaliado
O erro pode incluir mais campos dependendo da regra de validação específica, mas essas são as mais comuns. Você provavelmente achará propertyName e reason os campos mais úteis na resposta.
Agora podemos examinar os exemplos das diferentes regras de validação e ver como a nova mensagem detalhada nos ajuda a identificar o motivo da falha na validação.

Explorando uma coleção de amostras

Como exemplo, usaremos uma coleção de propriedades Real Estate em Nova York gerenciadas por uma equipe de Agentes Real Estate .
Aqui está um documento de amostra:
1{
2 "PID": "EV10010A1",
3 "agents": [ { "name": "Ana Blake", "email": "anab@rcgk.com" } ],
4 "description": "Spacious 2BR apartment",
5 "localization": { "description_es": "Espacioso apartamento de 2 dormitorios" },
6 "type": "Residential",
7 "address": {
8 "street1": "235 E 22nd St",
9 "street2": "Apt 42",
10 "city": "New York",
11 "state": "NY",
12 "zip": "10010"
13 },
14 "originalPrice": 990000,
15 "discountedPrice": 980000,
16 "geoLocation": [ -73.9826509, 40.737499 ],
17 "listedDate": "Wed Dec 11 2020 10:05:10 GMT-0500 (EST)",
18 "saleDate": "Wed Dec 21 2020 12:00:04 GMT-0500 (EST)",
19 "saleDetails": {
20 "price": 970000,
21 "buyer": { "id": "24434" },
22 "bids": [
23 {
24 "price": 950000,
25 "winner": false,
26 "bidder": {
27 "id": "24432",
28 "name": "Sam James",
29 "contact": { "email": "sjames@gmail.com" }
30 }
31 },
32 {
33 "price": 970000,
34 "winner": true,
35 "bidder": {
36 "id": "24434",
37 "name": "Joana Miles",
38 "contact": { "email": "jm@gmail.com" }
39 }
40 }
41 ]
42 }
43}

Usando o padrão de valor

Nossas propriedades imobiliárias são identificadas com o ID da propriedade (PID) que deve seguir um formato de nomenclatura específico: ele deve começar com duas letras seguidas de cinco dígitos e algumas letras e dígitos depois, assim: WS10011FG4 ou EV10010A1.
Podemos usar o operador JSON Schema pattern para criar uma regra para isso como uma expressão regular.
Validator:
1{
2 "$jsonSchema": {
3 "properties": {
4 "PID": {
5 "bsonType": "string",
6 "pattern": "^[A-Z]{2}[0-9]{5}[A-Z]+[0-9]+$"
7 }
8 }
9 }
10}
Se tentarmos inserir um documento com um campo PID que não corresponda ao padrão, por exemplo { PID: "apt1" }, receberemos um erro.
O erro informa que o campo PID tinha o valor de "apt1" e não corresponde à expressão regular, que foi especificada como "^[A-Z]{2}[0-9]{5}[A-Z]+[0-9]+$".
1{ ...
2 "schemaRulesNotSatisfied": [
3 {
4 "operatorName": "properties",
5 "propertiesNotSatisfied": [
6 {
7 "propertyName": "PID",
8 "details": [
9 {
10 "operatorName": "pattern",
11 "specifiedAs": {
12 "pattern": "^[A-Z]{2}[0-9]{5}[A-Z]+[0-9]+$"
13 },
14 "reason": "regular expression did not match",
15 "consideredValue": "apt1"
16 }
17 ]
18 }
19 ]
20 ...
21}

Propriedades adicionais e padrão de propriedade

A descrição pode estar localizada em vários idiomas. Atualmente, nosso aplicativo oferece suporte apenas a espanhol, alemão e francês, portanto, o objeto de localização só pode conter os campos description_es, description_deou description_fr. Outros campos não serão permitidos.
Podemos usar o operador patternProperties para descrever esse requisito como expressão regular e indicar que nenhum outro campo é esperado aqui com "additionalProperties": false.
Validator:
1{
2 "$jsonSchema": {
3 "properties": {
4 "PID": {...},
5 "localization": {
6 "additionalProperties": false,
7 "patternProperties": {
8 "^description_(es|de|fr)+$": {
9 "bsonType": "string"
10 }
11 }
12 }
13 }
14 }
15}
Documentos como este podem ser inseridos com sucesso:
1{
2 "PID": "TS10018A1",
3 "type": "Residential",
4 "localization": {
5 "description_es": "Amplio apartamento de 2 dormitorios",
6 "description_de": "Geräumige 2-Zimmer-Wohnung",
7 }
8}
Documentos como este falharão na verificação de validação:
1{
2 "PID": "TS10018A1",
3 "type": "Residential",
4 "localization": {
5 "description_cz": "Prostorný byt 2 + kk"
6 }
7}
O erro abaixo indica que o campo localization contém propriedades adicionais description_cz. description_cz não corresponde ao padrão esperado, portanto, é considerada uma propriedade adicional.
1{ ...
2 "propertiesNotSatisfied": [
3 {
4 "propertyName": "localization",
5 "details": [
6 {
7 "operatorName": "additionalProperties",
8 "specifiedAs": {
9 "additionalProperties": false
10 },
11 "additionalProperties": [
12 "description_cz"
13 ]
14 }
15 ]
16 }
17 ]
18...
19}

Enumeração de Opções Permitidas

Cada propriedade imobiliária em nossa collection tem um tipo, e queremos usar um dos quatro tipos: "Residencial," " Comercial," " Industrial," ou "Terreno." Isso pode ser feito com o operador enum.
Validator:
1{
2 "$jsonSchema": {
3 "properties": {
4 "type": {
5 "enum": [ "Residential", "Commercial", "Industrial", "Land" ]
6 }
7 }
8 }
9}
O seguinte documento será considerado inválido:
1{
2 "PID": "TS10018A1", "type": "House"
3}
O erro informa que o campo type falhou na validação porque "o valor não foi encontrado no enum."
1{...
2 "propertiesNotSatisfied": [
3 {
4 "propertyName": "type",
5 "details": [
6 {
7 "operatorName": "enum",
8 "specifiedAs": {
9 "enum": [
10 "Residential",
11 "Commercial",
12 "Industrial",
13 "Land"
14 ]
15 },
16 "reason": "value was not found in enum",
17 "consideredValue": "House"
18 }
19 ]
20 }
21 ]
22...
23}

Arrays: aplicação de número de elementos e exclusividade

Os agentes que gerenciam cada propriedade imobiliária são armazenados na matriz agents. Vamos nos certificar de que não haja elementos duplicados na matriz e que não haja mais de três agentes trabalhando com a mesma propriedade. Podemos usaruniqueItems e maxItems para isso.
1{
2 "$jsonSchema": {
3 "properties": {
4 "agents": {
5 "bsonType": "array",
6 "uniqueItems": true,
7 "maxItems": 3
8 }
9 }
10 }
11}
O documento a seguir viola ambas as regras de validação.
1{
2 "PID": "TS10018A1",
3 "agents": [
4 { "name": "Ana Blake" },
5 { "name": "Felix Morin" },
6 { "name": "Dilan Adams" },
7 { "name": "Ana Blake" }
8 ]
9}
O erro retorna informações sobre a falha de duas regras: "array não corresponde ao comprimento especificado" e "encontrou um item duplicado," e também indica qual valor era duplicado.
1{
2 ...
3 "propertiesNotSatisfied": [
4 {
5 "propertyName": "agents",
6 "details": [
7 {
8 "operatorName": "maxItems",
9 "specifiedAs": { "maxItems": 3 },
10 "reason": "array did not match specified length",
11 "consideredValue": [
12 { "name": "Ana Blake" },
13 { "name": "Felix Morin" },
14 { "name": "Dilan Adams" },
15 { "name": "Ana Blake" }
16 ]
17 },
18 {
19 "operatorName": "uniqueItems",
20 "specifiedAs": { "uniqueItems": true },
21 "reason": "found a duplicate item",
22 "consideredValue": [
23 { "name": "Ana Blake" },
24 { "name": "Felix Morin" },
25 { "name": "Dilan Adams" },
26 { "name": "Ana Blake" }
27 ],
28 "duplicatedValue": { "name": "Ana Blake" }
29 }
30 ]
31 ...
32 }

Aplicação de campos obrigatórios

Agora queremos garantir que haja informações de contato disponíveis para os agentes. Precisamos do nome de cada agente e pelo menos uma maneira de contatá-los: telefone ou e-mail. Usaremos requirede anyOf para criar esta regra.
Validator:
1{
2 "$jsonSchema": {
3 "properties": {
4 "agents": {
5 "bsonType": "array",
6 "uniqueItems": true,
7 "maxItems": 3,
8 "items": {
9 "bsonType": "object",
10 "required": [ "name" ],
11 "anyOf": [ { "required": [ "phone" ] }, { "required": [ "email" ] } ]
12 }
13 }
14 }
15 }
16}
O documento a seguir falhará na validação:
1{
2 "PID": "TS10018A1",
3 "agents": [
4 { "name": "Ana Blake", "email": "anab@rcgk.com" },
5 { "name": "Felix Morin", "phone": "+12019878749" },
6 { "name": "Dilan Adams" }
7 ]
8}
Aqui, o erro indica que o terceiro elemento da array ("itemIndex": 2) não corresponde à regra.
1{
2 ...
3 "propertiesNotSatisfied": [
4 {
5 "propertyName": "agents",
6 "details": [
7 {
8 "operatorName": "items",
9 "reason": "At least one item did not match the sub-schema",
10 "itemIndex": 2,
11 "details": [
12 {
13 "operatorName": "anyOf",
14 "schemasNotSatisfied": [
15 {
16 "index": 0,
17 "details": [
18 {
19 "operatorName": "required",
20 "specifiedAs": { "required": [ "phone" ] },
21 "missingProperties": [ "phone" ]
22 }
23 ]
24 },
25 {
26 "index": 1,
27 "details": [
28 {
29 "operatorName": "required",
30 "specifiedAs": { "required": [ "email" ] },
31 "missingProperties": [ "email" ]
32 }
33 ]
34 }
35 ]
36 }
37 ]
38 }
39 ]
40 }
41 ]
42...
43}

Criando dependências

Vamos criar outra regra para garantir que, se o documento contiver o camposaleDate, saleDetails também esteja presente e vice-versa: se houver saleDetails,saleDate também deverá existir.
1{
2 "$jsonSchema": {
3 "dependencies": {
4 "saleDate": [ "saleDetails"],
5 "saleDetails": [ "saleDate"]
6 }
7 }
8}
Agora, vamos tentar inserir o documento com saleDate, mas sem saleDetails:
1{
2 "PID": "TS10018A1",
3 "saleDate": Date("2020-05-01T04:00:00.000Z")
4}
O erro agora inclui a propriedade com dependência saleDate e uma propriedade ausente nas dependências: saleDetails.
1{
2 ...
3 "details": {
4 "operatorName": "$jsonSchema",
5 "schemaRulesNotSatisfied": [
6 {
7 "operatorName": "dependencies",
8 "failingDependencies": [
9 {
10 "conditionalProperty": "saleDate",
11 "missingProperties": [ "saleDetails" ]
12 }
13 ]
14 }
15 ]
16 }
17...
18}
Observe que, no JSON schema, o campo dependencies está no objeto raiz, e não dentro da propriedade específica. Portanto, na mensagem de erro, o objetodetails terá uma estrutura diferente:
1{ "operatorName": "dependencies", "failingDependencies": [...]}
Nos exemplos anteriores, quando a regra do JSON schema estava dentro do objeto "properties", assim:
1"$jsonSchema": { "properties": { "price": { "minimum": 0 } } }
os detalhes da mensagem de erro continham "operatorName": "properties" e um "propertyName":
1{ "operatorName": "properties",
2 "propertiesNotSatisfied": [ { "propertyName": "...", "details": [] } ]
3}

Adicionando lógica de negócios às suas regras de validação

Você pode usar a Linguagem de Query do MongoDB (MQL) em seu validador ao lado do JSON schema para adicionar uma lógica de negócios mais rica às suas regras.
Como um exemplo, você pode usar $expr para adicionar um check-in para que um discountPrice seja menor que originalPrice assim:
1{
2 "$expr": {
3 "$lt": [ "$discountedPrice", "$originalPrice" ]
4 },
5 "$jsonSchema": {...}
6}
$expr resolve para true ou falsee permite a você utilizar expressões de agregação para criar regras de negócio sofisticadas.
Para um exemplo um pouco mais complexo, digamos que mantemos uma matriz de lances no documento de cada propriedade imobiliária, e o campo booleano isWinner indica se um lance específico é o vencedor.
Documento de amostra:
1{
2 "PID": "TS10018A1",
3 "type": "Residential",
4 "saleDetails": {
5 "bids": [
6 {
7 "price": 500000,
8 "isWinner": false,
9 "bidder": {...}
10 },
11 {
12 "price": 530000,
13 "isWinner": true,
14 "bidder": {...}
15 }
16 ]
17 }
18}
Vamos nos certificar de que apenas um dos elementos da matriz bidspossa ser marcado como vencedor. O validador terá uma expressão em que aplicamos um filtro à matriz de lances para manter apenas os elementos com"isWinner": verdadeiro e verificar se o tamanho da matriz resultante é menor ou igual a 1.
Validator:
1{
2 "$and": [
3 {
4 "$expr": {
5 "$lte": [
6 {
7 "$size": {
8 "$filter": {
9 "input": "$saleDetails.bids.isWinner",
10 "cond": "$$this"
11 }
12 }
13 },
14 1
15 ]
16 }
17 },
18 {
19 "$expr": {...}
20 },
21 {
22 "$jsonSchema": {...}
23 }
24 ]
25}
Vamos tentar inserir o documento com poucos lances com "isWinner": true.
1{
2 "PID": "TS10018A1",
3 "type": "Residential",
4 "originalPrice": 600000,
5 "discountedPrice": 550000,
6 "saleDetails": {
7 "bids": [
8 { "price": 500000, "isWinner": true },
9 { "price": 530000, "isWinner": true }
10 ]
11 }
12}
A mensagem de erro produzida indicará qual expressão foi avaliada como falsa.
1{
2...
3 "details": {
4 "operatorName": "$expr",
5 "specifiedAs": {
6 "$expr": {
7 "$lte": [
8 {
9 "$size": {
10 "$filter": {
11 "input": "$saleDetails.bids.isWinner",
12 "cond": "$$this"
13 }
14 }
15 },
16 1
17 ]
18 }
19 },
20 "reason": "expression did not match",
21 "expressionResult": false
22 }
23...
24}

Validação geoespacial

Como último exemplo, vejamos como podemos usar as funcionalidades geoespaciais do MQL para garantir que todas as propriedades Real Estate na collection estejam localizadas dentro dos limites da cidade de Nova York. Nossos documentos incluem um campogeoLocation com coordenadas. Podemos utilizar $geoWithin para verificar se estas coordenadas estão dentro do polígono geoJSON (o polígono para a cidade de Nova York neste exemplo é aproximado).
Validator:
1{
2 "geoLocation": {
3 "$geoWithin": {
4 "$geometry": {
5 "type": "Polygon",
6 "coordinates": [
7 [ [ -73.91326904296874, 40.91091803848203 ],
8 [ -74.01626586914062, 40.75297891717686 ],
9 [ -74.05677795410156, 40.65563874006115 ],
10 [ -74.08561706542969, 40.65199222800328 ],
11 [ -74.14329528808594, 40.64417760251725 ],
12 [ -74.18724060058594, 40.643656594948524 ],
13 [ -74.234619140625, 40.556591288249905 ],
14 [ -74.26345825195312, 40.513277131087484 ],
15 [ -74.2510986328125, 40.49500373230525 ],
16 [ -73.94691467285156, 40.543026009954986 ],
17 [ -73.740234375, 40.589449604232975 ],
18 [ -73.71826171874999, 40.820045086716505 ],
19 [ -73.78829956054686, 40.8870435151357 ],
20 [ -73.91326904296874, 40.91091803848203 ] ]
21 ]
22 }
23 }
24 },
25 "$jsonSchema": {...}
26}
Um documento como este será inserido com sucesso.
1{
2 "PID": "TS10018A1",
3 "type": "Residential",
4 "geoLocation": [ -73.9826509, 40.737499 ],
5 "originalPrice": 600000,
6 "discountedPrice": 550000,
7 "saleDetails": {...}
8}
O documento a seguir falhará.
1{
2 "PID": "TS10018A1",
3 "type": "Residential",
4 "geoLocation": [ -73.9826509, 80.737499 ],
5 "originalPrice": 600000,
6 "discountedPrice": 550000,
7 "saleDetails": {...}
8}
O erro indicará que a validação falhou no operador$geoWithin, e o motivo é "nenhuma das geometrias consideradas estava contida na geometria da expressão."
1{
2...
3 "details": {
4 "operatorName": "$geoWithin",
5 "specifiedAs": {
6 "geoLocation": {
7 "$geoWithin": {...}
8 }
9 },
10 "reason": "none of the considered geometries were contained within the
11 expression's geometry",
12 "consideredValues": [ -73.9826509, 80.737499 ]
13 }
14...
15}

Conclusão e próximas etapas

A validação do esquema é uma ótima ferramenta para impor a governança sobre seus conjuntos de dados. Você tem a opção de Express as regras de validação utilizando JSON schema, MongoDB Query Language ou ambos. E agora, com as mensagens de erro detalhadas, fica ainda mais fácil de usar, e você pode ter as regras tão sofisticadas quanto você precisar, sem o risco de manutenção dispendiosa.
Você pode encontrar o código validador completo e documentos de exemplo desta publicação aqui.
Se você quiser avaliar esse recurso e nos fornecer um feedback antecipado, preencha este formulário para participar do programa de pré-visualização.
Mais postagens sobre validação de esquema:
Questões? Comentários? Queremos muito nos conectar com você. Participe da conversa nos fóruns da MongoDB Community.
Porto seguro
O desenvolvimento, o lançamento e o timing de quaisquer recursos ou funcionalidades descritos dos nossos produtos permanecem a nosso exclusivo critério. Esta informação destina-se apenas a delinear a direção geral do nosso produto e não deve ser invocada na tomada de uma decisão de compra nem é um compromisso, promessa ou obrigação legal de entregar qualquer material, código ou funcionalidade.

Ícone do FacebookÍcone do Twitterícone do linkedin
Avalie esse anúncio
star-empty
star-empty
star-empty
star-empty
star-empty
Relacionado
Tutorial

Construindo com padrões: o Padrão Outlier


May 16, 2022 | 3 min read
exemplo de código

Salvando dados no Unity3D usando SQLite


Sep 07, 2022 | 13 min read
Início rápido

Início rápido: tipos de dados BSON - ObjectId


Sep 23, 2022 | 3 min read
Artigo

As 4 principais razões pelas quais você deve usar o MongoDB


Sep 23, 2022 | 9 min read
Sumário