Ao terminar esta aula, você vai conseguir
- Transformar requisitos de busca em um modelo de documento
- Montar dados e consultas incrementais para o catálogo
- Definir provas para escrita, resumo e desempenho
O projeto final é um catálogo de cursos com busca por status, área, nível e carga horária. Você vai transformar essas perguntas em documento, operações e provas. O projeto não inclui API, autenticação ou deploy; o foco é a camada de dados e a capacidade de explicar cada decisão.
Pense num catálogo de biblioteca. A ficha contém as informações usadas para encontrar o item, enquanto relatórios respondem quantos existem por assunto. No MongoDB, o documento reúne os campos de leitura frequente, filtros localizam itens e agregações geram resumos. O limite da analogia é que um sistema real precisa lidar com concorrência, permissões, falhas e recuperação.
Escreva os requisitos como consultas
O catálogo precisa listar somente cursos publicados, filtrar por nível e ordenar por nota. Um documento inicial pode ser:
{
slug: 'css-responsivo',
titulo: 'CSS responsivo',
area: 'front-end',
nivel: 'iniciante',
status: 'rascunho',
cargaHoras: 6,
nota: 4.6,
instrutor: { id: 'inst-12', nome: 'Ana' }
}O resumo do instrutor é incorporado porque aparece em cada card. O identificador
permite localizar a fonte completa. Antes de aceitar duplicação, defina como uma
mudança de nome será propagada. slug será a chave pública legível e precisa
ser único.
Escreva um contrato curto antes dos comandos. titulo, slug, status,
nivel e cargaHoras são obrigatórios; carga é número positivo; status pertence
a uma lista conhecida. A validação do cliente melhora a conversa com o usuário,
mas não substitui validação na API e na coleção. Qualquer cliente capaz de falar
com o servidor pode enviar dados fora da interface.
Prepare regras e dados de teste
Em um servidor de prática isolado, crie o índice único antes de depender dele:
db.cursos.createIndex({ slug: 1 }, { unique: true })
db.cursos.insertMany([
{
slug: 'css-responsivo',
titulo: 'CSS responsivo',
area: 'front-end',
nivel: 'iniciante',
status: 'rascunho',
cargaHoras: 6,
nota: 4.6
},
{
slug: 'api-node',
titulo: 'API com Node',
area: 'back-end',
nivel: 'intermediario',
status: 'publicado',
cargaHoras: 9,
nota: 4.9
}
])Tentar inserir css-responsivo novamente reproduz um erro de chave duplicada.
Esse é um resultado desejável: o banco protege a regra. A aplicação deve
traduzir o erro para uma mensagem útil, não desativar o índice.
Use dados de teste claramente descartáveis e um banco separado. Assim, repetir o roteiro não modifica o catálogo de produção. Antes de apagar a coleção para recomeçar, confirme o nome do banco e prefira remover apenas os registros de teste identificados pelo próprio projeto.
Publique e consulte com provas
Atualize o estado usando o slug e confira as contagens:
const escrita = db.cursos.updateOne(
{ slug: 'css-responsivo', status: 'rascunho' },
{ $set: { status: 'publicado' } }
)
escrita.matchedCount
escrita.modifiedCount
db.cursos
.find(
{ status: 'publicado', nivel: 'iniciante' },
{ titulo: 1, nota: 1, _id: 0 }
)
.sort({ nota: -1, slug: 1 })O estado anterior no filtro impede que uma segunda publicação silenciosa seja
contada como mudança. Espere matchedCount e modifiedCount iguais a um na
primeira execução e zero modificado na repetição.
Uma operação que lê e depois escreve pode encontrar concorrência. Quando a mudança depende do estado anterior, mantenha essa condição no filtro, como no exemplo. Para fluxos com várias escritas dependentes, estude transações e as garantias necessárias; não envolva todo comando numa transação por hábito.
Resuma e prepare a leitura frequente
db.cursos.aggregate([
{ $match: { status: 'publicado' } },
{ $group: { _id: '$nivel', total: { $sum: 1 } } },
{ $sort: { total: -1, _id: 1 } }
])
db.cursos.createIndex({ status: 1, nivel: 1, nota: -1 })O índice candidato segue a consulta da listagem. Confirme com explain em dados
representativos; não declare ganho apenas porque o índice existe.
O relatório por nível deve ter uma saída prevista. Com dois publicados iniciantes e um intermediário, espere dois grupos com totais 2 e 1. Se uma carga horária em texto for ignorada por uma média posterior, corrija o dado e a regra de entrada em vez de esconder a divergência no pipeline.
O laboratório desta página é um simulador didático de filtros sobre JSON local.
Ele não persiste, não cria índice, não agrega e não se conecta ao MongoDB. Use
somente igualdade, $gte, $gt, $lte, $lt, $ne e $in. O filtro inicial
deve devolver três cursos. Acrescente "nivel":"iniciante" e espere dois.
Sua missão final é manter um registro com consulta, resultado previsto e resultado observado para inserção, publicação, busca e resumo. Se divergirem, investigue tipo, filtro e estágio antes de alterar o modelo. Assim, o catálogo termina como um sistema explicável, não apenas um conjunto de comandos.
Laboratório ao vivo
Busca final do catálogo
Filtre cursos publicados com pelo menos seis horas e depois refine por nível. Este simulador lê JSON local; não é um servidor MongoDB.
Resultado
Pare e pense
Qual é a melhor prova de que uma atualização do projeto funcionou?
As contagens distinguem correspondência de mudança, e a releitura confirma o estado final que a aplicação passará a consumir.
Faça sem copiar
Acrescente um curso, publique-o, filtre por área, gere o resumo por nível e registre a saída esperada de cada etapa antes de executar no MongoDB real.
Fontes para consultar
Terminou a missão?
Marque apenas quando você conseguir explicar o conceito e concluir o desafio. O progresso fica salvo somente neste navegador.
Voltar ao curso e ver seu progresso →