Guia completo
MongoDB do zero: guia de banco de dados por documentos
Entenda documentos, coleções, BSON, CRUD, modelagem, aggregation e índices no MongoDB com uma livraria prática e um roteiro de estudo completo.
MongoDB é um sistema de banco de dados que guarda registros como documentos, agrupados em coleções. Ao terminar este guia, você terá uma pequena livraria rodando, saberá ler a estrutura dos dados e terá um caminho claro para estudar CRUD, modelagem, aggregation e índices.
O nome técnico é banco de dados orientado a documentos. Em português direto: em vez de obrigar cada informação a caber primeiro numa linha dividida em colunas fixas, o MongoDB permite guardar um objeto inteiro, com listas e objetos internos, como uma unidade. Esse objeto é persistido em BSON, uma representação binária que amplia os tipos disponíveis no JSON.
Isso não significa “jogar qualquer objeto no banco”. Um bom documento tem uma fronteira pensada, tipos coerentes, regras para dados importantes e índices que acompanham as consultas reais. A flexibilidade tira uma obrigação do formato; ela não tira a responsabilidade de modelar.
Da sacola da livraria ao documento no banco
Imagine a Livraria Horizonte preparando um pedido para entrega. Dentro de uma pasta vão o endereço usado naquela compra, os itens, o preço de cada item, as quantidades, o total e o status. Quem abre a pasta encontra o retrato daquela venda sem buscar uma folha diferente para cada detalhe.
Esse é um bom paralelo para um documento MongoDB. A pasta é o documento; o nome
escrito na lombada é o _id; os campos preenchidos são os pares de chave e
valor; a lista de itens é um array; endereço é um documento incorporado. O
arquivo com todas as pastas de pedidos é a coleção pedidos.
O paralelo tem limite. MongoDB não é um armário físico e não lê necessariamente uma pasta por vez. Ele executa filtros sobre conjuntos, usa índices, mantém cache, replica dados e pode distribuir coleções entre servidores. Além disso, colocar tudo na mesma “pasta” não é sempre correto: uma lista que cresce sem limite ou um dado compartilhado por milhares de registros pode pedir uma coleção separada e referências.
Veja como um pedido pode ficar. Não é uma sequência de tabelas montada na hora; é o agregado que a tela de confirmação costuma ler junto:
{
"_id": "pedido-1",
"clienteId": "cliente-1",
"entrega": {
"rua": "Rua das Flores",
"numero": 120,
"cidade": "Campinas"
},
"itens": [
{
"livroId": "livro-1",
"titulo": "JavaScript do zero",
"precoUnitario": 39.9,
"quantidade": 2
}
],
"total": 79.8,
"status": "pago"
}O clienteId é uma referência; o endereço e o item são cópias incorporadas.
Essa mistura é intencional. O cadastro atual do cliente pode mudar, mas um
pedido antigo deve continuar mostrando para onde foi enviado e quanto custou.
Modelar MongoDB é decidir quais dados precisam viver e mudar juntos.
Servidor, database, coleção, documento e campo
No começo, é comum chamar tudo de “Mongo”. Separar os nomes evita confusão nas configurações e nos erros:
- MongoDB Server é o processo
mongodque recebe conexões e persiste dados; - database é um espaço lógico, como
livraria; - collection agrupa documentos de um assunto, como
livros; - document é um registro composto por campos e valores;
- field é uma propriedade, como
titulo,estoqueoueditora.cidade; - MongoDB Node.js Driver é a biblioteca oficial usada pela aplicação para conversar com o servidor.
Uma coleção lembra uma tabela porque as duas agrupam registros do mesmo assunto. Mas a comparação para aí. Documentos de uma coleção podem não ter todos os mesmos campos, e um campo pode conter outro documento ou uma lista. É possível exigir formatos com validação, porém essa regra é uma decisão sua, não uma consequência automática de criar a coleção.
Todo documento precisa de _id, sua identidade única na coleção. Se você não
enviar o campo, o driver normalmente cria um ObjectId. Nos exemplos deste
cluster usamos ids de texto, como livro-1, para que as saídas possam ser
repetidas e comparadas. Em um projeto, escolha o tipo de id uma vez e mantenha o
contrato; alternar texto, número e ObjectId para a mesma entidade complica
filtros e referências.
JSON na aparência, BSON de verdade
O documento parece JSON quando aparece no terminal, mas o formato armazenado é
BSON. BSON suporta tipos que JSON puro não expressa diretamente, como
ObjectId, Date, Decimal128, dados binários e inteiros de tamanhos
específicos.
Essa diferença aparece quando uma API transforma o resultado em JSON. Um
ObjectId ou Decimal128 precisa de uma representação textual compatível; uma
data pode virar string ISO. Portanto, “parece um objeto JavaScript” não quer
dizer “todos os tipos são iguais aos do JavaScript”. O driver faz a conversão
entre os dois mundos, mas sua aplicação ainda precisa decidir o contrato que
entrega ao navegador.
No laboratório, preco: 39.9 mantém a leitura simples. Em contabilidade real,
o tipo é decisão de domínio: centavos inteiros evitam frações; Decimal128
guarda decimal de alta precisão; Number usa ponto flutuante binário. O banco
não sabe sozinho qual arredondamento sua empresa exige.
Por que usamos MongoDB 8.0.28
Em 22 de agosto de 2026, a documentação apresenta 8.3 como a linha atual, mas o próprio versionamento do MongoDB separa linhas major e minor. Linhas major, como 8.0, têm ciclo de cinco anos e são indicadas quando se quer uma janela previsível e controle manual de atualização. Linhas minor entregam recursos antes e pedem atualizações mais frequentes.
Para um curso que precisa continuar reproduzível, minha escolha é a linha major
8.0 no patch estável mais recente: 8.0.28, publicado em 22 de julho de 2026. Não
há release candidate nem recurso preview no caminho principal. O driver usado é
o oficial mongodb 7.5.0. Isso não declara que 8.3 seja instável; declara apenas
que previsibilidade é mais importante para este laboratório.
Suba um MongoDB descartável com Docker
O comando abaixo publica a porta padrão somente para o laboratório local. Ele
não configura senha, persistência nem réplica; portanto, não é uma receita de
produção. Antes de executar, confirme que você não possui outro serviço usando
a porta 27017 nem um container chamado mongo-devclub.
docker run -d \
--name mongo-devclub \
-p 127.0.0.1:27017:27017 \
mongo:8.0.28
docker exec mongo-devclub \
mongosh --quiet --eval 'db.adminCommand({ ping: 1 })'O mongod é o servidor. mongosh é um cliente de terminal executado dentro do
container. O retorno ok: 1 prova que o cliente conseguiu mandar um comando ao
servidor; ele não prova que sua aplicação Node está usando a mesma URI.
Mantenha o container ativo durante os próximos exemplos; o comando de remoção fica no fim do guia. Se você quiser dados duráveis, autenticação, backup e alta disponibilidade, planeje essas partes separadamente ou use um serviço gerenciado. Um container sem volume perde seu banco quando é removido — o que aqui é proteção contra acidente, não defeito.
O primeiro acesso com o driver oficial do Node.js
Crie uma pasta vazia, inicialize o projeto e instale o driver. Mongoose não entra neste começo porque queremos enxergar a API que conversa diretamente com o MongoDB:
mkdir livraria-mongo
cd livraria-mongo
npm init -y
npm install mongodb@7.5.0Crie index.mjs. MongoClient representa o cliente; a URI aponta para o
servidor; db() escolhe o database. O comando ping força uma ida ao banco e
evita confundir “objeto do cliente criado” com “conexão comprovada”.
import { MongoClient } from "mongodb";
const uri = process.env.MONGODB_URI ?? "mongodb://127.0.0.1:27017";
const client = new MongoClient(uri);
try {
await client.connect();
const db = client.db("livraria");
const resposta = await db.command({ ping: 1 });
console.log({ conexao: resposta.ok === 1 ? "ok" : "falhou" });
} finally {
await client.close();
}finally fecha o cliente até quando uma operação falha. Numa API de longa
duração, a prática comum é criar um MongoClient reutilizável durante a vida do
processo, em vez de abrir e fechar uma conexão para cada requisição. Neste
script curto, fechar no final deixa a execução previsível.
Crie, leia e altere um livro
Agora o banco começa a assumir uma responsabilidade real. collection()
seleciona livros; insertOne() cria um documento. Se a coleção ainda não
existir, a primeira inserção pode criá-la implicitamente.
const livros = client.db("livraria").collection("livros");
const resultado = await livros.insertOne({
_id: "livro-1",
titulo: "JavaScript do zero",
preco: 39.9,
estoque: 8,
categorias: ["programação", "javascript"],
});
console.log({
acknowledged: resultado.acknowledged,
insertedId: resultado.insertedId,
});acknowledged: true diz que o servidor confirmou a escrita segundo a
configuração usada. Não significa que toda regra de negócio imaginável foi
validada; neste ponto, por exemplo, ainda não criamos uma regra contra estoque
negativo.
Para ler somente os campos de que a tela precisa, use filtro e projeção:
const livro = await livros.findOne(
{ _id: "livro-1" },
{ projection: { _id: 0, titulo: 1, preco: 1, estoque: 1 } },
);
console.log(livro);O primeiro objeto é o filtro: qual documento pode entrar no resultado. O
segundo contém a projeção: quais campos voltam. _id aparece por padrão, então
_id: 0 o retira dessa resposta.
Uma venda de duas unidades pode ser expressa com condição e operador atômico:
const alteracao = await livros.updateOne(
{ _id: "livro-1", estoque: { $gte: 2 } },
{ $inc: { estoque: -2 } },
);
console.log({
matchedCount: alteracao.matchedCount,
modifiedCount: alteracao.modifiedCount,
});
console.log(await livros.findOne(
{ _id: "livro-1" },
{ projection: { _id: 0, estoque: 1 } },
));$gte significa “maior ou igual”; $inc incrementa o valor pelo número
informado, que pode ser negativo. A condição e a alteração acontecem na mesma
operação sobre o documento. Isso é mais seguro do que ler 8 no Node, calcular
6 e depois gravar: entre a leitura e a gravação, outra compra poderia mudar o
estoque.
A próxima lição abre esses conceitos com calma em documentos e coleções. Depois, o CRUD com Node.js reúne create, read, update e delete num único script.
Flexível não quer dizer sem regra
Por padrão, dois documentos na mesma coleção podem ter campos diferentes. Isso
ajuda catálogos variados: livro físico pode ter peso; e-book pode ter
formatoArquivo. Entretanto, certas regras não são opcionais. Um pedido sem
itens ou um estoque negativo não vira aceitável só porque BSON consegue
representá-lo.
MongoDB permite validação com $jsonSchema. A coleção abaixo exige título,
preço e estoque, aceita os tipos numéricos BSON usados no exemplo e recusa
estoque menor que zero:
await db.createCollection("livros_validados", {
validator: {
$jsonSchema: {
bsonType: "object",
required: ["titulo", "preco", "estoque"],
properties: {
titulo: { bsonType: "string" },
preco: {
bsonType: ["double", "int", "long", "decimal"],
minimum: 0,
},
estoque: { bsonType: "int", minimum: 0 },
},
},
},
});Ao tentar inserir estoque: -1, o servidor devolve o código 121:
try {
await db.collection("livros_validados").insertOne({
titulo: "Livro inválido",
preco: 20,
estoque: -1,
});
} catch (erro) {
console.log({ codigo: erro.code, motivo: "estoque abaixo de zero" });
}A validação no banco protege qualquer cliente, não apenas uma rota da API. Ela não elimina a validação de entrada: a API ainda deve devolver uma mensagem boa ao usuário e impedir trabalho desnecessário. As duas camadas resolvem problemas diferentes.
Incorporar ou referenciar é a decisão central
Incorporar é colocar o dado relacionado dentro do documento. Referenciar é guardar um identificador que aponta para outro documento. Não existe regra “MongoDB sempre incorpora”. Existe pergunta sobre acesso, crescimento e consistência.
No pedido, incorporar o endereço de entrega preserva o histórico e permite ler a confirmação de uma vez. Referenciar o cliente evita repetir todo o cadastro em cada compra. Incorporar milhares de avaliações dentro de um livro pode fazer o documento crescer sem limite; manter avaliações em outra coleção pode ser mais adequado.
Minha regra prática é começar pela tela ou operação mais importante: quais dados ela lê e altera junto? Depois confronto esse desenho com crescimento, duplicação e necessidade de atualização. A lição de modelagem MongoDB faz essa decisão em um pedido completo e mostra onde uma transação entra.
Aggregation pipeline é uma linha de preparo
Quando a pergunta deixa de ser “qual é este livro?” e vira “quais livros mais faturaram?”, uma busca simples não basta. O aggregation pipeline passa documentos por estágios. Um estágio filtra, outro abre arrays, outro agrupa e o seguinte ordena.
Pense na bancada de expedição: a primeira pessoa separa somente pedidos pagos; a segunda abre cada caixa e coloca os itens na esteira; a terceira reúne itens do mesmo título; a quarta ordena pelo valor vendido. Cada etapa recebe o resultado da anterior. O limite: o banco pode otimizar partes da execução, usar memória, disco e índices; não existe uma pessoa nem uma caixa material em cada estágio.
const ranking = await pedidos.aggregate([
{ $match: { status: "pago" } },
{ $unwind: "$itens" },
{
$group: {
_id: "$itens.titulo",
unidades: { $sum: "$itens.quantidade" },
},
},
{ $sort: { unidades: -1 } },
]).toArray();
console.log(ranking);aggregate() devolve cursor; toArray() consome esse cursor e materializa os
resultados. Em bases grandes, não transforme qualquer consulta em array sem
pensar em limite e memória. A lição de
aggregation pipeline
constrói o relatório estágio por estágio e reproduz uma falha de expressão.
Índice é um atalho que também cobra manutenção
Sem um índice adequado, MongoDB pode percorrer todos os documentos para atender um filtro. Um índice mantém valores de campos em uma estrutura ordenada para reduzir o espaço de busca. No catálogo, é como um índice alfabético que aponta para as fichas: procurar “Node.js” deixa de exigir abrir cada pasta.
O limite dessa imagem é o custo. Um índice real ocupa disco e memória, e cada
escrita precisa atualizá-lo. Criar um índice para todo campo deixa inserções mais
caras e não garante que o planejador vá escolhê-los. Índice nasce de consulta
frequente observada, e explain("executionStats") mostra o que realmente foi
examinado.
No laboratório de 80 mil pedidos, a mesma consulta examinou 80 mil documentos
com COLLSCAN. Depois do índice composto, examinou 20 chaves, zero documentos e
usou IXSCAN, porque a projeção estava coberta. A medição completa e seus
limites estão em índices no MongoDB.
MongoDB ou PostgreSQL: a escolha que eu faria
“NoSQL ou SQL?” é amplo demais. Eu começo pela forma como o domínio mantém consistência e pelas consultas mais valiosas. Esta tabela é uma decisão editorial para um projeto novo, não uma lei sobre produtos:
| Situação observada | Minha primeira opção | Por quê | O que eu validaria antes |
|---|---|---|---|
| agregado lido junto, com campos que variam por subtipo | MongoDB | documento acompanha o objeto e permite incorporar partes | crescimento do documento e consultas cruzadas |
| muitas relações obrigatórias e relatórios combinando entidades | PostgreSQL | chaves, constraints e joins expressam o centro do domínio | volume, formato dos relatórios e competência do time |
| pedido precisa preservar endereço e preço da compra | MongoDB com snapshot incorporado | histórico sai numa leitura e muda como unidade | duplicação aceitável e limite do documento |
| financeiro com regras relacionais densas | PostgreSQL | integridade relacional e SQL tornam regras explícitas | necessidade real de escala e transações concorrentes |
| catálogo heterogêneo, como livros, cursos e kits | MongoDB | documentos podem ter atributos próprios por tipo | validação mínima comum e estratégia de índices |
| equipe domina profundamente uma das duas opções | a opção dominada, se atender os requisitos | operação conhecida costuma valer mais que novidade | requisitos que de fato forçariam migração |
Minha assinatura aqui é simples: não escolho MongoDB para evitar aprender modelagem. Eu o escolho quando a fronteira de documento explica o domínio e reduz trabalho sem esconder uma rede de relações que o produto realmente precisa consultar. Se o problema é naturalmente relacional, o guia de PostgreSQL oferece uma comparação concreta.
O mapa do cluster MongoDB
Estude as lições na ordem. Cada uma usa a mesma Livraria Horizonte, mas recria seu database para que você possa repetir a missão:
| Ordem | Lição | Resultado verificável |
|---|---|---|
| 11 | Documentos e coleções | criar coleção, consultar campo aninhado e provocar validação 121 |
| 12 | CRUD com Node.js | inserir, filtrar, alterar e remover com o driver oficial |
| 13 | Modelagem MongoDB | escolher incorporação e referência e confirmar uma transação |
| 14 | Aggregation pipeline | produzir ranking de vendas e juntar clientes com $lookup |
| 15 | Índices MongoDB | medir COLLSCAN e IXSCAN sobre a mesma consulta |
Os números começam em 11 porque a trilha de banco de dados já ensina primeiro os fundamentos relacionais. Você não precisa “esquecer SQL” para aprender documentos; comparar os modelos torna cada decisão mais consciente.
Depois das cinco lições, o tutorial API REST com MongoDB, validação e testes reúne o driver oficial, Express, schema da coleção, índice único, paginação e aggregation numa API completa executada em Docker.
O laboratório comprova mecanismo, não operação de produção
Rodar os exemplos localmente prova que o servidor 8.0.28 aceitou os comandos, que o driver 7.5.0 converteu os valores e que as saídas mostradas correspondem àquele estado. Isso é uma evidência importante, mas tem uma fronteira: o container de um nó não prova disponibilidade, recuperação de desastre, capacidade, segurança nem comportamento sob concorrência real.
Antes de levar a livraria ao ar, transforme requisitos operacionais em testes. Defina quem pode conectar e o que cada usuário pode fazer; habilite autenticação e transporte seguro; planeje backup e restauração; escolha uma topologia com redundância; observe conexões, latência, espaço e consultas lentas. Um backup só vira proteção depois que uma restauração foi ensaiada.
Também não copie os 80 mil pedidos sintéticos da aula de índices como previsão
de produção. Eles foram desenhados para tornar uma diferença visível e
repetível. Seus dados terão outras proporções de status, clientes mais ativos,
documentos maiores e períodos de pico. Capture os filtros e ordenações que a
aplicação realmente envia, use explain num ambiente seguro e acompanhe o custo
das escritas depois de adicionar índices.
Essa separação evita duas conclusões perigosas: “funcionou no Docker, então está pronto” e “o banco é complexo demais para começar”. O laboratório ensina os controles; a produção acrescenta responsabilidades mensuráveis. Você começa pequeno sem fingir que pequeno e definitivo são a mesma coisa.
Missão: prove que o banco mudou, não apenas que o script rodou
Com o container ativo e index.mjs conectado, faça três mudanças: cadastre
livro-2 com estoque 5, retire duas unidades usando filtro com $gte e consulte
somente titulo e estoque. Sua evidência de conclusão é esta sequência:
insertedId: livro-2
matchedCount: 1
modifiedCount: 1
documento final: { titulo: 'Node.js na prática', estoque: 3 }Depois altere a quantidade solicitada para 99. O resultado correto é
matchedCount: 0, e o estoque deve continuar 3. Essa segunda tentativa é a
parte importante: ela comprova que o filtro representa uma regra, e não apenas
um caminho feliz decorado.
Com a missão conferida, encerre o recurso local. Este comando remove somente o
container chamado mongo-devclub criado no começo do guia:
docker rm -f mongo-devclubTrilha
Banco de dados
SQL, PostgreSQL, MongoDB e Prisma: modelar, consultar e conectar o banco na API que você escreveu.
node.js
API REST com MongoDB: validação, paginação e testes
Perguntas frequentes
MongoDB é um banco sem estrutura?
MongoDB substitui PostgreSQL em qualquer projeto?
Preciso usar Mongoose para acessar MongoDB no Node.js?
Qual versão do MongoDB este guia usa?
Posso guardar preço como Number no MongoDB?
O código deste guia foi executado em MongoDB 8.0.28, MongoDB Node.js Driver 7.5.0, Node 26.3.0 e Docker 29.5.3, e as saídas exibidas são as reais — como produzimos este conteúdo.
Fontes consultadas
- MongoDB Manual — Introduction to MongoDB — mongodb.com
- MongoDB Manual — MongoDB Versioning — mongodb.com
- MongoDB Manual — Release Notes 8.0 — mongodb.com
- MongoDB Manual — CRUD Operations — mongodb.com
- MongoDB Node.js Driver — mongodb.com
