Pular para o conteúdo
Cursos

DevClub

LógicaFront-endBack-endMobile

IA Club

IA na prática
Estudar programaçãoEstudar IA

Aula 6 de 6

Projeto MongoDB: catálogo de cursos pesquisável

Reúna modelagem, CRUD, consultas, agregação e índice em um catálogo de cursos com critérios claros de verificação e limites conhecidos.

70 minutos · leitura + prática · nível iniciante

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
Três documentos independentes guardam nome e estado ativo.

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:

javascript
{
  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:

javascript
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:

javascript
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

javascript
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.

Pare e pense

Qual é a melhor prova de que uma atualização do projeto funcionou?

Escolha uma resposta
Missão da aula

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 →