Bancos de documentos
Dados guardados como documentos aninhados, com esquema flexível e as consultas que isso dificulta.
As decisões num banco de documentos são cinco: o que embutir, como lidar com listas grandes, quanto esquema impor, como garantir a consistência e quando um banco de documentos é a escolha certa.
O que embutir
A pergunta que guia a modelagem é como os dados são lidos, e não como se relacionam. Comece pelas telas e pelas consultas mais frequentes.
| Relação | Padrão | Exemplo |
|---|---|---|
| Um para poucos, lidos juntos | Embutir | Endereços do cliente, itens do pedido |
| Um para muitos, lidos separados | Referenciar: o filho guarda o identificador do pai | Pedidos do cliente: cada pedido tem cliente_id |
| Um para milhões | Referenciar no filho, nunca uma lista no pai | Eventos de um sensor, acessos de um usuário |
| Muitos para muitos | Lista de identificadores num dos lados, ou nos dois | Alunos e turmas |
| Dado compartilhado lido junto | Embutir uma cópia parcial, e referenciar o original | Nome e foto do autor em cada comentário |
Padrões que resolvem casos comuns
| Padrão | Como funciona | Quando |
|---|---|---|
| Subconjunto | Embute os itens mais usados (os 10 comentários mais recentes) e guarda o resto em outra coleção | A tela mostra só uma parte da lista |
| Cópia parcial (extended reference) | Embute só os campos do outro documento que a tela usa | Nome do cliente no pedido |
| Balde (bucket) | Agrupa muitos itens pequenos em documentos por período ou quantidade | Medições de sensores, uma hora por documento |
| Versão do esquema | Um campo versao_esquema em cada documento | Documentos de formas diferentes convivendo durante uma migração |
| Valor calculado | Guarda um total ou uma contagem, atualizado a cada mudança | Número de comentários de uma postagem |
Listas grandes
No teste do nível Conceito, uma postagem estourou o limite de 16 MB com 15.500 comentários de 1 KB. Bem antes disso, cada leitura da postagem carregava megabytes de comentários.
| Saída | Como |
|---|---|
| Coleção própria | Comentários com postagem_id e índice; a postagem guarda só a contagem |
| Subconjunto | A postagem guarda os 10 últimos; o resto fica na coleção própria |
| Limite explícito | $push com $slice mantém só os N mais recentes, quando o histórico antigo não importa |
Quanto esquema impor
| Nível | Como | Quando |
|---|---|---|
| Nenhum | Qualquer documento entra | Protótipos, e nada mais |
| Na aplicação | Tipos e validação no código (Zod, Pydantic, classes) | Sempre, como primeira barreira |
| No banco | $jsonSchema na coleção | Campos obrigatórios, tipos e valores permitidos que nenhuma versão pode violar |
| No banco, em modo de aviso | validationAction: "warn" | Coleções antigas, para descobrir os documentos fora do padrão antes de recusar |
A validação no banco pega o que a aplicação deixa passar: uma versão antiga do código ainda rodando, um script de correção, uma importação. No teste, a coleção sem validação devolveu 745 de 894 pedidos numa consulta de faturamento, porque 149 tinham o total em texto. Com o $jsonSchema, esse documento foi recusado na gravação.
A validação não é retroativa: documentos que já estavam na coleção continuam lá. Para encontrá-los, consulte com $jsonSchema no filtro, ou procure tipos com $type.
Como garantir a consistência
| Operação | Como fazer |
|---|---|
| Alterar um documento com uma condição | Condição no filtro e alteração com operadores ($inc, $set, $push) no mesmo comando |
| Alterar vários documentos juntos | Transação entre documentos (exige conjunto de réplicas) |
| Cópias de dados compartilhados | Atualizar as cópias com updateMany, numa tarefa em segundo plano, ou aceitar que fiquem como estavam (o preço na compra) |
| Unicidade | Índice único, como no relacional |
A primeira linha é a mais importante: no teste, ler, conferir e gravar vendeu 30 unidades de um estoque de 10; a atualização condicional vendeu 10.
Documentos, relacional com jsonb, ou os dois
| Banco de documentos (MongoDB) | PostgreSQL com jsonb | |
|---|---|---|
| Junções e transações entre várias tabelas | Possíveis, mas caras e menos naturais | Naturais |
| Documentos aninhados e esquema variável | O modelo principal | Numa coluna, com índices GIN |
| Escala horizontal com particionamento | Embutida (sharding) | Extensões e serviços (Citus) |
| Consultas sobre documentos | Linguagem própria e pipelines de agregação | SQL com operadores de jsonb |
| Busca no teste: pedidos com um produto, 100 mil documentos, com índice | 1 ms | 0,53 ms |
O banco de documentos é a escolha natural quando os dados são de fato documentos, lidos e gravados inteiros, com formas que variam (catálogos com atributos diferentes por categoria, conteúdo, perfis, configurações), e quando a escala horizontal embutida pesa. Quando os dados são relacionais e só uma parte varia, uma coluna jsonb resolve sem um segundo banco.
Resumo da decisão
- Modele pelas leituras: embuta o que é lido junto e tem tamanho limitado.
- Referencie o que cresce sem limite ou é compartilhado.
- Valide o esquema no banco com
$jsonSchema, além da aplicação. - Atualizações condicionais atômicas, nunca ler, conferir e gravar.
- Índices nos campos aninhados consultados.
- Transações entre documentos só como exceção; se forem a regra, o modelo é relacional.
O próximo nível mostra a atualização condicional nas cinco linguagens e a validação de esquema.
Prompts para aprofundar
Ao abrir no ChatGPT ou no Claude, o prompt é enviado ao serviço escolhido pela URL e também fica copiado na sua área de transferência.
Modelar meus dados em documentos
Quero modelar os dados do meu sistema num banco de documentos. Pergunte o que o sistema faz, quais são as telas e consultas mais frequentes, o volume de cada tipo de dado e quais dados mudam com frequência. Proponha os documentos, explicando para cada relação se embute ou referencia e por quê, quais padrões de modelagem se aplicam, a validação de esquema de cada coleção e os índices. No final, aponte as partes que ficariam melhores num banco relacional.
MongoDB ou PostgreSQL com jsonb
Estou decidindo entre um banco de documentos e o PostgreSQL com colunas jsonb. Pergunte como são os meus dados, quanto da estrutura varia, que consultas e relatórios preciso, se há operações que alteram vários registros juntos e qual é a escala esperada. Compare para o meu caso: modelagem, consistência, consultas, índices, escala horizontal, operação e custo. Recomende uma opção e explique o que eu perderia com a outra.
Migrar a forma dos documentos
Preciso mudar a forma dos documentos de uma coleção que já tem milhões de registros. Pergunte qual é a mudança, qual banco e linguagem eu uso e como é o deploy. Compare: migrar tudo de uma vez em lotes, migrar na leitura com um campo de versão do esquema, e manter as duas formas para sempre. Monte comigo o plano escolhido, com o código que lê as duas formas, a validação durante a transição e como saber que terminou.