Cheat Sheet: MongoDB Associate Developer (Java) Certification
Resumo prático dos tópicos cobrados na certificação, pensado para consulta rápida
1. Modelo de documentos e BSON
MongoDB guarda dados como documentos BSON dentro de coleções. Cada documento é um conjunto de pares chave-valor, e o valor pode ser um escalar, um array ou outro documento (aninhamento).
Diferente de uma tabela relacional, documentos de uma mesma coleção não precisam ter o mesmo formato. Isso é o chamado schema flexível: dá pra evoluir o modelo sem migração custosa, misturar formatos diferentes na mesma coleção, e ainda assim aplicar regras de validação quando fizer sentido.
Get Murilo Luzzi’s stories in your inbox
Join Medium for free to get updates from this writer.
Tipos BSON principais:
- Texto →
string - Número decimal simples→
double - Número decimal preciso (ex. operações bancárias)→
decimal128 - Inteiro 32 bits →
int - Inteiro 64 bits →
long - Documento aninhado →
object - Lista →
array - Booleano →
bool - Data →
date - Identificador único →
objectId - Nulo →
null - Binário →
binData - Regex →
regex - Timestamp interno →
timestamp - Min/Max key →
minKey/maxKey
Dica: a pergunta clássica é “esses 3 documentos de formatos diferentes podem coexistir na mesma coleção?” — a resposta quase sempre é sim, contanto que cada um tenha
_idúnico. MongoDB não exige schema fixo.
2. Operadores
Comparação (usados em filtros)
{campo: valor}→ igualdade implícita$eq/$ne→ igual / diferente$gt/$gte→ maior / maior ou igual$lt/$lte→ menor / menor ou igual$in/$nin→ está / não está em uma lista
Lógicos
$and→ todas as condições verdadeiras (vírgula já é AND implícito)$or→ pelo menos uma condição verdadeira$nor→ nenhuma condição verdadeira$not→ inverte uma condição
Array e elemento
$exists→ verifica se o campo existe$type→ verifica o tipo BSON do campo$all→ array contém todos os valores citados (ordem livre)$size→ array tem exatamente N elementos$elemMatch→ um único elemento do array satisfaz todas as condições
Dica: sem
$elemMatch,{nota: {$gt: 80, $lt: 90}}pode ser satisfeito por elementos diferentes do array (um >80, outro <90). Com$elemMatch, precisa ser o mesmo elemento. É a pegadinha mais comum da prova.
Atualização (só dentro de update)
$set→ define/cria valor de um campo$unset→ remove um campo$inc→ soma (ou subtrai, com negativo) um valor numérico$setOnInsert→ só aplica se a operação criar um documento novo (upsert)$push→ adiciona item ao final do array$addToSet→ adiciona ao array só se não existir (evita duplicata)$pull→ remove elementos que casam com uma condição$pop→ remove primeiro (-1) ou último (1) item do array
Projection
1inclui,0exclui.- Não dá pra misturar inclusão e exclusão — exceto
_id, que pode ser0mesmo com outros campos em1. $slicelimita quantos itens de um array retornar.
Estágios de aggregation
$match→ filtra documentos (igual aofind)$group→ agrupa por uma chave e aplica acumuladores$project/$set→ molda/adiciona campos na saída$sort/$limit→ ordena / limita resultado$unwind→ "explode" um array em um documento por item$lookup→ join com outra coleção (left outer join)$out→ grava o resultado em uma coleção, substituindo o conteúdo existente — precisa ser o último estágio$search→ busca Atlas Search — precisa ser o primeiro estágio
Acumuladores do $group
$sum, $avg, $max, $min, $push (junta em array), $addToSet (junta valores únicos)
3. Comandos na prática (shell)
Inserir
db.pedidos.insertOne({ cliente: "Ana", total: 150 })
db.pedidos.insertMany([
{ cliente: "Ana", total: 150 },
{ cliente: "Bruno", total: 90 }
])Buscar
// igualdade simples
db.pedidos.find({ cliente: "Ana" })
// comparação
db.pedidos.find({ total: { $gte: 100 } })
// valor dentro de um array
db.pedidos.find({ itens: "caneca" })
// $elemMatch: mesmo elemento satisfaz as duas condições
db.pedidos.find({
itens: { $elemMatch: { produto: "caneca", qtd: { $gt: 1 } } }
})
// lógico
db.pedidos.find({ $or: [{ status: "pendente" }, { total: { $gt: 500 } }] })Atualizar
// $set em um campo específico
db.pedidos.updateOne({ _id: 1 }, { $set: { status: "pago" } })
// substitui o documento inteiro (sem operadores)
db.pedidos.replaceOne({ _id: 1 }, { cliente: "Ana", total: 200 })
// upsert: cria se não existir
db.pedidos.updateOne(
{ cliente: "Carla" },
{ $set: { total: 80 } },
{ upsert: true }
)
// vários documentos de uma vez
db.pedidos.updateMany({ total: { $lt: 50 } }, { $set: { promo: true } })
// busca, atualiza e já retorna o documento (evita condição de corrida)
db.pedidos.findAndModify({
query: { _id: 1 },
update: { $inc: { total: 10 } },
new: true
})Deletar
// Deleta o primeiro documento encontrado que passa pelo filtro
db.pedidos.deleteOne({ _id: 1 })
// Deleta todos os documentos que passam pelo filtro
db.pedidos.deleteMany({ status: "cancelado" })Ordenar, limitar e contar
// use _id como critério extra pra garantir ordem consistente
db.pedidos.find().sort({ total: -1, _id: 1 }).limit(3)
// countDocuments() substituiu deprecado count() e é muito preciso
db.pedidos.countDocuments({ status: "pago" })Projeção
// inclui só os campos citados (+ _id, a menos que zere)
db.pedidos.find({ status: "pago" }, { cliente: 1, total: 1, _id: 0 })
// exclui campos específicos
db.pedidos.find({}, { endereco: 0 })Índices
// índice simples
db.pedidos.createIndex({ cliente: 1 })
// único
db.pedidos.createIndex({ email: 1 }, { unique: true })
// composto - ordem recomendada: Equality, Sort, Range (regra "ESR")
db.pedidos.createIndex({ status: 1, total: -1, cliente: 1 })
// ver índices existentes
db.pedidos.getIndexes()
// checar se a query usa índice (IXSCAN) ou varre tudo (COLLSCAN)
db.pedidos.explain().find({ total: { $gt: 100 } })
// remover
db.pedidos.dropIndex("cliente_1")
db.pedidos.dropIndexes()Lendo o explain(): o plano de execução mostra os estágios que a query passou. Os principais:
COLLSCAN→ varreu a coleção inteira, sem usar índice (sinal de alerta de performance)IXSCAN→ usou um índice pra localizar os documentos (bom)FETCH→ precisou buscar o documento completo no disco/memória depois do índiceSORT→ teve que ordenar os resultados em memória porque o índice não cobria a ordenação pedida
Dica: array indexado vira automaticamente um índice multikey — não precisa criar nada diferente, só indexar o campo normalmente. E: apagar um índice não apaga dados, só faz a query voltar a fazer COLLSCAN.
Aggregation
Pipeline é uma sequência de estágios — a saída de um vira a entrada do próximo.
// Esqueleto do Aggregation
db.collection.aggregate([
{
$stage1: {
// expressão 1,
// expressão 2
}
},
{
$stage2: {
// expressão 1
}
}
])// $match + $group: filtra e depois soma por grupo
db.pedidos.aggregate([
{ $match: { status: "pago" } },
{ $group: { _id: "$cliente", totalGasto: { $sum: "$total" } } },
{ $sort: { totalGasto: -1 } },
{ $limit: 5 }
])
// $project / $set: reformata e cria campo calculado
db.pedidos.aggregate([
{ $match: { status: "pago" } },
{ $set: { totalComDesconto: { $multiply: ["$total", 0.9] } } },
{ $project: { cliente: 1, total: 1, totalComDesconto: 1, _id: 0 } }
])
// $count: retorna um único documento com a contagem
db.pedidos.aggregate([
{ $match: { status: "pendente" } },
{ $count: "totalPendentes" }
])
// $unwind: "explode" o array de itens em um documento por item
db.pedidos.aggregate([
{ $unwind: "$itens" },
{ $group: { _id: "$itens.produto", vendidos: { $sum: 1 } } }
])
// $lookup: join com a coleção "clientes" (left outer join)
// $lookup sempre retorna um array - $unwind é comum logo depois
db.pedidos.aggregate([
{
$lookup: {
from: "clientes",
localField: "clienteId",
foreignField: "_id",
as: "dadosCliente"
}
},
{ $unwind: "$dadosCliente" }
])
// $out: grava o resultado final em outra coleção (substitui se já existir)
db.pedidos.aggregate([
{ $match: { status: "pago" } },
{ $group: { _id: "$cliente", totalGasto: { $sum: "$total" } } },
{ $out: "resumo_clientes" }
])Dica: a ordem dos estágios importa para o resultado (e para performance —
$matchcedo reduz o volume de dados nos estágios seguintes), mas não para a sintaxe: cada estágio é sempre um objeto independente dentro do array.
4. Java Driver
O que é o driver
O MongoDB Java Driver é a biblioteca oficial que traduz chamadas Java em comandos que o banco entende (protocolo de rede do MongoDB). A aplicação nunca fala direto com o banco — ela usa MongoClient, MongoDatabase e MongoCollection<Document> como camadas de abstração.
MongoClient mongoClient = MongoClients.create(connectionString);
MongoDatabase db = mongoClient.getDatabase("loja");
MongoCollection<Document> pedidos = db.getCollection("pedidos");Componentes da URI de conexão
mongodb+srv://usuario:senha@cluster.mongodb.net/loja?retryWrites=true&w=majoritymongodb+srv://→ protocolo (+srvresolve o cluster via DNS, comum no Atlas)usuario:senha→ credenciais de autenticaçãocluster.mongodb.net→ host/cluster de destino/loja→ banco de dados padrão da conexão?retryWrites=true&w=majority→ opções (retry automático, nível de confirmação de escrita)
Connection pooling
O driver não abre uma conexão nova a cada operação — ele mantém um pool de conexões já estabelecidas e reaproveitáveis. Isso reduz a latência (evita handshake TCP/TLS repetido) e permite lidar com múltiplas operações concorrentes de forma eficiente. O MongoClient deve ser criado uma única vez e reaproveitado durante todo o ciclo de vida da aplicação — nunca um MongoClient por requisição.
Insert
// um documento
pedidos.insertOne(new Document("cliente", "Ana").append("total", 150));
// vários documentos
List<Document> novos = List.of(
new Document("cliente", "Bruno").append("total", 90),
new Document("cliente", "Carla").append("total", 60)
);
InsertManyResult resultado = pedidos.insertMany(novos);
resultado.getInsertedIds().forEach((i, id) -> System.out.println(id));Find
Os filtros usam a classe utilitária Filters (import static com.mongodb.client.model.Filters.*), que evita montar Document na mão.
// um único documento
Document doc = pedidos.find(eq("cliente", "Ana")).first();
// vários documentos, com cursor
try (MongoCursor<Document> cursor =
pedidos.find(and(gte("total", 100), eq("status", "pago"))).iterator()) {
while (cursor.hasNext()) {
System.out.println(cursor.next().toJson());
}
}Update
Assim como Filters, existe a classe Updates (import static com.mongodb.client.model.Updates.*) para montar as operações de atualização.
// um documento
Bson filtro = eq("_id", 1);
Bson atualizacao = Updates.combine(Updates.set("status", "pago"), Updates.inc("total", 10));
pedidos.updateOne(filtro, atualizacao);
// vários documentos
pedidos.updateMany(lt("total", 50), Updates.set("promo", true));Delete
// um documento
DeleteResult r1 = pedidos.deleteOne(eq("_id", 1));
System.out.println(r1.getDeletedCount());
// vários documentos
DeleteResult r2 = pedidos.deleteMany(eq("status", "cancelado"));
System.out.println(r2.getDeletedCount());Aggregate
O pipeline é montado como uma List<Bson>, geralmente com a classe Aggregates (import static com.mongodb.client.model.Aggregates.*) combinada com Accumulators para os estágios de $group.
Bson match = Aggregates.match(eq("status", "pago"));
Bson group = Aggregates.group("$cliente", Accumulators.sum("totalGasto", "$total"));
Bson sort = Aggregates.sort(Sorts.descending("totalGasto"));
pedidos.aggregate(List.of(match, group, sort))
.forEach(d -> System.out.println(d.toJson()));Dica: o driver Java tem versões “cruas” (passar
Document/Bsonmontado manualmente) e versões com builders (Filters,Updates,Aggregates,Sorts,Projections). A prova costuma cobrar reconhecer a sintaxe correta dos builders — vale decorar os imports estáticos mais comuns.
5. Dicas rápidas para a prova
$elemMatché o tópico mais cobrado dentro de arrays — sem ele, condições podem "vazar" entre elementos diferentes.- Projeção não mistura inclusão e exclusão, exceto
_id. $outprecisa ser o último estágio e substitui a coleção de destino se ela já existir; use$mergese quiser só atualizar.$searchprecisa ser o primeiro estágio do pipeline.- Índice composto: ordem dos campos segue a regra ESR (Equality, Sort, Range) para máxima eficiência.
- Índice cobre a query (query covered) quando todos os campos pedidos — filtro, sort e projeção — estão no índice, evitando ida ao disco (
PROJECTION_COVEREDnoexplain()). explain():COLLSCAN= sem índice (ruim),IXSCAN= usando índice (bom).- Upsert só usa
$setOnInsertquando de fato cria um documento novo; se o filtro já encontrar um documento, esse operador é ignorado. findAndModifycomnew: trueretorna o documento já atualizado; sem isso, retorna o estado anterior — importante em cenários de concorrência.- Array indexado = índice multikey automaticamente, sem sintaxe especial.






