Olá, dev! Seja bem-vindo ao Dia 05 do seu plano de preparação para a certificação MongoDB Associate Developer. Hoje estudaremos a base de performance do MongoDB: os Índices. Compreender como as estruturas B-tree funcionam e como escolher as propriedades corretas é essencial tanto para o exame quanto para o ambiente de produção.
1. O que são Índices e por que usá-los?
Sem índices, uma consulta precisa realizar um COLLSCAN (Collection Scan), varrendo cada documento da coleção do início ao fim no disco. Os índices armazenam uma estrutura ordenada em árvore B (B-tree) em memória RAM contendo uma porção menor dos dados, permitindo localizar rapidamente a posição exata do documento no arquivo de dados através de um IXSCAN (Index Scan).
2. Tipos Fundamentais de Índices
A. Índice de Campo Único (Single Field Index)
// Criando um índice de campo único no campo 'email'
db.usuarios.createIndex({ email: 1 })
O valor 1 indica ordem ascendente e -1 indica ordem descendente. Em índices de campo único, a direção não faz diferença para a ordenação, pois o MongoDB pode navegar na B-tree em ambas as direções com a mesma eficiência.
B. Índice Composto (Compound Index)
Índice formado por múltiplos campos. A ordem dos campos e a direção no índice composto são críticas.
db.pedidos.createIndex({ status: 1, dataCriacao: -1 })
A Regra dos Prefixos do Índice (Index Prefixes):
Um índice composto em { a: 1, b: 1, c: 1 } possui os seguintes prefixos:
{ a: 1 }{ a: 1, b: 1 }{ a: 1, b: 1, c: 1 }
Consultas que filtram por a, ou por a e b, utilizarão o índice. Porém, uma consulta que filtra apenas por `b` ou `c` não poderá utilizar o índice.
C. Índice Multikey (Indexação de Arrays)
Quando você cria um índice em um campo cujo valor é um array, o MongoDB cria automaticamente um Multikey Index, adicionando uma chave na B-tree para cada elemento individual do array.
// 'habilidades' é um array de strings
db.developers.createIndex({ habilidades: 1 })
3. Propriedades Especiais de Índices (Index Properties)
A. Unique Index (Índice Único)
Garante que a coleção não contenha valores duplicados para o campo indexado.
db.usuarios.createIndex({ cpf: 1 }, { unique: true })
Armadilha do Exame: Se múltiplos documentos forem inseridos sem o campo cpf, o MongoDB atribuirá null a todos eles, o que causará erro de duplicidade no segundo documento. Para evitar isso, combina-se com sparse ou partialFilterExpression.
B. TTL Index (Time-To-Live)
Remove automaticamente documentos da coleção após um determinado período. Muito utilizado para sessões, tokens temporários e logs.
// Expira documentos 3600 segundos (1 hora) após a data informada em 'dataCriacao'
db.sessoes.createIndex(
{ dataCriacao: 1 },
{ expireAfterSeconds: 3600 }
)
Regra de Validação: O campo indexado por TTL deve obrigatoriamente ser do tipo BSON Date. O thread de expiração do MongoDB executa a cada 60 segundos.
C. Sparse Index (Índice Esparso)
Indexa apenas os documentos que possuem o campo especificado. Documentos que não contêm o campo são completamente omitidos da B-tree, economizando espaço.
db.usuarios.createIndex({ telefone: 1 }, { sparse: true })
D. Partial Index (Índice Parcial)
Mais flexível e poderoso que o Sparse Index. Permite definir uma expressão de filtro para determinar exatamente quais documentos devem ser indexados.
// Indexa o campo email apenas para usuários ativos
db.usuarios.createIndex(
{ email: 1 },
{ partialFilterExpression: { status: "ATIVO" } }
)
4. Comandos Utilitários em `mongosh`
// Listar todos os índices da coleção
db.usuarios.getIndexes()
// Remover um índice específico pelo nome
db.usuarios.dropIndex("email_1")
// Verificar o tamanho consumido pelos índices
db.usuarios.totalIndexSize()
5. Questões no Estilo Exame de Certificação
Questão 1: Uma aplicação possui uma coleção com o índice composto { categoria: 1, preco: -1, marca: 1 }. Qual das consultas a seguir NÃO conseguirá utilizar este índice?
A) db.produtos.find({ categoria: "Eletrônicos" })
B) db.produtos.find({ categoria: "Eletrônicos", preco: { $lt: 1000 } })
C) db.produtos.find({ preco: 500, marca: "Sony" })
D) db.produtos.find({ categoria: "Eletrônicos", preco: 500, marca: "Sony" })
Resposta Correta: C. A consulta C tenta filtrar por preco e marca sem incluir o primeiro campo do prefixo (categoria). Sem o prefixo inicial, o MongoDB não pode utilizar o índice composto.
Questão 2: Um desenvolvedor tenta criar o índice { "enderecos.cep": 1, "telefones.numero": 1 }. Onde enderecos é um array de objetos e telefones também é um array de objetos. O que acontecerá ao executar o comando de criação de índice?
A) O índice será criado normalmente como um Multikey Index.
B) O MongoDB retornará um erro informando que um índice composto não pode conter mais de um campo do tipo array.
C) O índice será criado, mas consultas que buscam ambos os campos falharão em runtime.
D) O MongoDB converterá automaticamente o segundo campo para uma string.
Resposta Correta: B. O MongoDB proíbe estritamente a criação de índices compostos Multikey em que mais de um campo seja um array.