Objetivos de aprendizado
Depois de ler este artigo, você vai conseguir:
- Entender como o modelo de documentos e o modelo relacional se diferenciam
- Comparar joins, transações, JSON e índices com exemplos que funcionam
- Escolher entre MongoDB e PostgreSQL para o seu tipo de projeto
MongoDB e PostgreSQL estão entre os bancos de dados mais usados em aplicações web, APIs e bots. Os dois guardam e consultam os seus dados, mas com modelos diferentes. O PostgreSQL organiza os dados em tabelas com esquema fixo e as liga com joins. O MongoDB guarda documentos parecidos com JSON dentro de collections.
A escolha certa depende do formato dos seus dados e de como você os lê, e as seções abaixo comparam os dois ponto a ponto, com código. Se ainda está escolhendo entre famílias de bancos, comece por qual banco de dados escolher.
O que é cada um?#
PostgreSQL é um banco de dados relacional de código aberto. Você define tabelas com colunas tipadas, e as consultas usam SQL. Linhas de tabelas diferentes se ligam por chaves estrangeiras. Veja o que é PostgreSQL para o básico.
MongoDB é um banco de documentos. Um registro é um documento BSON (uma forma binária de JSON) com objetos e arrays aninhados, e os documentos ficam em collections que não impõem um esquema fixo. As consultas usam a API própria do MongoDB e o pipeline de agregação, não SQL. Veja o que é MongoDB.
Quais são as diferenças, lado a lado?#
| Critério | PostgreSQL | MongoDB |
|---|---|---|
| Modelo | Tabelas, linhas, colunas | Collections de documentos |
| Esquema | Definido antes, imposto pelo banco | Flexível por padrão |
| Linguagem de consulta | SQL | API do MongoDB e pipeline de agregação |
| Relações | Chaves estrangeiras e JOIN |
Documentos embutidos, ou $lookup na agregação |
| Transações | ACID, o jeito normal de trabalhar | ACID entre documentos, com custo extra |
| JSON | Coluna jsonb, indexável com GIN |
Formato nativo |
| Limite de tamanho | 1 GB por campo | 16 MiB por documento |
| Escala horizontal | Réplicas de leitura, particionamento | Replica sets e sharding embutido |
Como o modelo de dados muda o seu projeto?#
Pense num pedido com um cliente e dois itens. No MongoDB, o normal é embutir tudo num documento só:
{
_id: "ord_1001",
customer: { name: "Ana", email: "ana@example.com" },
items: [
{ sku: "A-1", qty: 2, price: 19.9 },
{ sku: "B-7", qty: 1, price: 49.0 }
],
status: "paid"
}Uma leitura devolve o pedido inteiro. A documentação do MongoDB recomenda embutir os dados que são lidos juntos. O custo é a duplicação: se o e-mail do cliente muda, todo pedido que o embutiu continua com o valor antigo, a menos que você atualize todos.
No PostgreSQL, você divide os mesmos dados em tabelas relacionadas:
CREATE TABLE customers (
id bigint GENERATED ALWAYS AS IDENTITY PRIMARY KEY,
name text NOT NULL,
email text NOT NULL UNIQUE
);
CREATE TABLE orders (
id bigint GENERATED ALWAYS AS IDENTITY PRIMARY KEY,
customer_id bigint NOT NULL REFERENCES customers (id),
status text NOT NULL
);
CREATE TABLE order_items (
order_id bigint NOT NULL REFERENCES orders (id),
sku text NOT NULL,
qty int NOT NULL CHECK (qty > 0),
price numeric(10,2) NOT NULL
);O e-mail fica num lugar só, e o banco recusa um pedido de um cliente que não existe. Ler um pedido completo exige um join, que é barato quando as colunas de chave estrangeira têm índice.
Como funcionam joins e relações?#
No PostgreSQL, joins são o centro da linguagem:
SELECT o.id, c.name, i.sku, i.qty
FROM orders o
JOIN customers c ON c.id = o.customer_id
JOIN order_items i ON i.order_id = o.id
WHERE o.status = 'paid';O MongoDB também faz join. O estágio $lookup executa um left outer join com uma collection do mesmo banco:
db.orders.aggregate([
{ $match: { status: "paid" } },
{ $lookup: {
from: "customers",
localField: "customerId",
foreignField: "_id",
as: "customer"
} }
]);Funciona, mas é a exceção num projeto com MongoDB, não o padrão. Se a maioria das suas consultas precisa de dados de três ou quatro collections ao mesmo tempo, você está brigando com o modelo, e o PostgreSQL vai parecer mais natural.
Como as transações se comparam?#
O PostgreSQL gira em torno de transações: todo comando roda dentro de uma, e BEGIN ... COMMIT agrupa vários. Até um ALTER TABLE pode rodar dentro de uma transação.
No MongoDB, a gravação num único documento é atômica, incluindo os objetos e arrays aninhados. Ele também suporta transações ACID com vários documentos em replica sets e sharded clusters. Só que elas têm limites: por padrão, uma transação precisa terminar em 60 segundos (a configuração transactionLifetimeLimitSeconds), e transações longas pressionam o cache de armazenamento. A documentação orienta manter as transações curtas e modelar os dados para que a maioria das operações toque um documento só.
Para movimentar dinheiro, contar estoque ou qualquer caso em que dois registros precisam mudar juntos, o PostgreSQL faz do caminho seguro o padrão.
Como cada um lida com JSON?#
O PostgreSQL guarda JSON numa coluna jsonb e pode indexá-la com GIN:
CREATE TABLE events (id bigserial PRIMARY KEY, payload jsonb NOT NULL);
CREATE INDEX events_payload_gin ON events USING GIN (payload);
SELECT id FROM events WHERE payload @> '{"type": "signup"}';Esse modelo híbrido é um bom meio-termo: colunas normais para os campos estáveis e uma coluna jsonb para a parte que varia. A documentação do PostgreSQL recomenda jsonb em vez de json para a maioria das aplicações. Você só abre mão das ferramentas que o MongoDB criou para documentos, como o pipeline de agregação.
No MongoDB, a mesma consulta é nativa:
db.events.find({ type: "signup" });Como eles escalam?#
Na maioria dos projetos, o primeiro limite que aparece é um índice faltando ou RAM de menos, não o motor do banco. Resolva isso primeiro.
Depois desse ponto, os caminhos se separam. O PostgreSQL costuma escalar primeiro na vertical (mais RAM e CPU) e depois adiciona réplicas de leitura e particionamento de tabelas. O MongoDB tem sharding embutido: divide uma collection entre servidores por uma chave de shard. Isso ajuda com volumes muito grandes, mas a chave de shard é uma decisão de projeto que precisa ser tomada cedo. Para entender os termos, veja collection, cluster e replica set.
Quando escolher cada um?#
Escolha PostgreSQL se os seus dados são muito relacionados (usuários, pedidos, pagamentos), você precisa de restrições e joins, faz relatórios com SQL ou quer um banco de uso geral como padrão para um projeto novo.
Escolha MongoDB se os registros são independentes e variam de formato (catálogos com atributos diferentes, conteúdo, logs de eventos, perfis), você os lê inteiros e o seu time já trabalha com objetos JSON no Node.js.
Na dúvida, escolha PostgreSQL para dados relacionais e use jsonb onde precisar de flexibilidade. Trocar depois é possível, mas dá trabalho de verdade. Para uma comparação dentro da família SQL, veja PostgreSQL vs MySQL.
Como fazer isso na Square Cloud#
A Square Cloud oferece hospedagem de MongoDB e PostgreSQL a partir do plano Standard, junto com MySQL e Redis. O plano Hobby não inclui hospedagem de banco.
Você cria o banco no painel, sempre em uma versão recente, e ele fica pronto em segundos no mesmo datacenter das suas aplicações (cerca de 1 ms de latência média), com TLS obrigatório. Os dois rodam como nó único (standalone), então o MongoDB não tem replica set. O PostgreSQL é o nativo, sem extensões. Você escolhe o motor, conecta a aplicação com a URL de conexão que o painel entrega e controla o resto.
Você tira snapshots manuais quando quiser, e todo plano com bancos inclui também um snapshot automático diário. Dá para restaurar um snapshot no mesmo banco, em outro do mesmo motor ou num banco novo. Os dois motores podem conviver no mesmo plano, cada um com pelo menos 1024 MB da RAM, então dá para testar a comparação acima com os seus próprios dados antes de decidir.
Veja hospedagem de bancos de dados, hospedagem de MongoDB e hospedagem de PostgreSQL.
Hospedagem de bancos
MongoDB, PostgreSQL, MySQL e Redis no mesmo datacenter do app
Perguntas frequentes
MongoDB é mais rápido que PostgreSQL?
Nenhum é mais rápido em todos os casos: a velocidade depende do modelo de dados, dos índices e da consulta. O MongoDB é rápido para ler um documento inteiro pela chave, e o PostgreSQL, em joins e agregações sobre tabelas relacionadas. Teste com os seus dados.
O MongoDB tem transações como o PostgreSQL?
Sim. O MongoDB suporta transações ACID com vários documentos em replica sets e sharded clusters. Elas custam mais que gravações em um único documento, por isso a documentação recomenda modelar os dados para que a maioria das operações toque um documento só.
O PostgreSQL consegue guardar JSON como o MongoDB?
Sim. O tipo jsonb guarda JSON em formato binário e pode ser indexado com GIN. Você continua com SQL, joins e restrições no resto dos dados, mas não ganha o pipeline de agregação do MongoDB.
Dá para migrar do MongoDB para o PostgreSQL depois?
Dá, mas dá trabalho. Você precisa desenhar as tabelas, decidir o que fica em jsonb, reescrever as consultas do pipeline de agregação em SQL e mover os dados. Escolher bem no início sai mais barato.
Qual é melhor para quem está começando?
O PostgreSQL ensina SQL, uma habilidade que serve no MySQL e na maioria dos outros bancos. O MongoDB é rápido de começar se você já pensa em objetos JSON. Os dois têm bons drivers oficiais para Node.js e Python.
Mais em Bancos de dados
Ver todos os 24 artigos- Quanto custa um banco de dados na nuvem?Um banco de dados na nuvem custa de zero a centenas de dólares por mês. Veja o que define o preço: instância, disco, tráfego, snapshots e como estimar o seu.
- Como hospedar um banco de dados (e conectar sua aplicação)Para hospedar um banco de dados, escolha o motor, crie a instância, guarde a string de conexão em variável de ambiente e teste a conexão. Veja o passo a passo.
- O que é Redis e para que serveRedis é um banco de dados em memória que guarda pares chave-valor e estruturas de dados. Veja como funciona, para que serve e quando não usar.
- Como fazer backup do banco de dados (MySQL, PostgreSQL, MongoDB)Faça backup de MySQL, PostgreSQL e MongoDB com mysqldump, pg_dump e mongodump, e restaure o dump. Veja os comandos, como verificar e os erros comuns.