Dia 02 de 15

Arquitetura MongoDB & Operações CRUD (Parte 1)

1. Arquitetura do MongoDB & Storage Engine WiredTiger

O MongoDB armazena dados em documentos BSON organizados em Collections (equivalentes a tabelas no modelo relacional), que por sua vez residem em Databases.

2. Operações de Inserção: insertOne() vs insertMany()

No MongoDB Shell (mongosh), a criação de documentos é realizada através das rotinas insertOne() e insertMany().

2.1 insertOne()

Insere um único documento na coleção. Se o campo _id não for fornecido explicitamente, o driver/servidor gera automaticamente um ObjectId de 12 bytes.

db.produtos.insertOne({
  nome: "Teclado Mecânico Custom",
  categoria: "Periféricos",
  preco: 450.00,
  estoque: 15,
  tags: ["teclado", "rgb", "switches-brown"]
});

2.2 insertMany() e a opção { ordered: true | false }

Insere um array de documentos em lote. Esta opção é um dos pontos mais cobrados no exame de certificação!

// Exemplo de inserção desordenada (unordered)
db.usuarios.insertMany([
  { _id: 1, nome: "Alice" },
  { _id: 2, nome: "Bob" },
  { _id: 2, nome: "Carlos" }, // Erro de Chave Duplicada!
  { _id: 3, nome: "Diana" }
], { ordered: false });

// Resultado com ordered: false -> Alice, Bob e Diana serão inseridos com sucesso. Carlos falhará.

3. Operações de Consulta: find() e findOne()

O método find(query, projection) retorna um Cursor para os documentos que correspondem aos critérios de busca.

3.1 Modificadores do Cursor (Sort, Skip, Limit)

A ordem encadeada de chamadas no shell não altera a ordem de execução do servidor. O MongoDB sempre aplica os modificadores na sequência otimizada:

  1. sort() - Ordena os resultados.
  2. skip() - Pula N documentos.
  3. limit() - Limita a quantidade máxima de retorno.
// Retorna os 5 produtos mais caros da categoria 'Periféricos', pulando os 2 primeiros
db.produtos.find({ categoria: "Periféricos" })
           .sort({ preco: -1 }) // -1 para decrescente, 1 para crescente
           .skip(2)
           .limit(5);

4. Operadores de Consulta (Query Operators)

4.1 Operadores de Comparação

Operador Significado Exemplo Explicativo
$eq / $ne Igual / Diferente { status: { $ne: "INATIVO" } }
$gt / $gte Maior / Maior ou Igual { preco: { $gte: 100.00 } }
$lt / $lte Menor / Menor ou Igual { idade: { $lt: 18 } }
$in / $nin Em / Não contido em array { cidade: { $in: ["Uberaba", "SP"] } }

4.2 Operadores Lógicos

4.3 Operadores de Elemento

// Busca documentos que contêm o campo 'desconto' E cujo valor seja do tipo número
db.vendas.find({
  desconto: { $exists: true, $type: "number" }
});

5. Projeções (Projections)

A projeção determina quais campos devem ser retornados no documento de resposta. Isso reduz drasticamente a sobrecarga de rede e o consumo de memória RAM.

// VÁLIDO: Projeção de Inclusão (retorna apenas nome, preco e suprime o _id)
db.produtos.find({}, { nome: 1, preco: 1, _id: 0 });

// VÁLIDO: Projeção de Exclusão (retorna todos os campos EXCETO estoque e dataCriacao)
db.produtos.find({}, { estoque: 0, dataCriacao: 0 });

// INVÁLIDO (Gera Erro MongoServerError): Mistura de 1 e 0
db.produtos.find({}, { nome: 1, preco: 0 }); // ERRO!

6. Questões Simuladas para a Certificação

Teste seus conhecimentos com questões reais no padrão da prova oficial MongoDB Associate Developer Exam.

Questão 01:

A coleção clientes atualmente possui 0 documentos. Um desenvolvedor executa o seguinte comando em uma coleção vazia:

db.clientes.insertMany([
  { _id: 10, nome: "Ana" },
  { _id: 20, nome: "Bruno" },
  { _id: 20, nome: "Caio" },
  { _id: 30, nome: "Daniela" }
], { ordered: true });

Qual será o estado da coleção clientes após a execução e qual será o resultado retornado?

Alternativas:

A) Nenhum documento será inserido porque a operação é atômica e falha inteiramente no erro de chave duplicada.

B) Os documentos de Ana (_id: 10) e Bruno (_id: 20) serão inseridos. A operação é interrompida no documento de Caio e Daniela não é inserida.

C) Os documentos de Ana (_id: 10), Bruno (_id: 20) e Daniela (_id: 30) serão inseridos com sucesso.

D) Todos os 4 documentos serão inseridos, com o MongoDB gerando um novo _id automático para Caio.

Ver Gabarito Comentado

Resposta Correta: B

Explicação: Por padrão, insertMany possui { ordered: true }. O MongoDB processa os documentos sequencialmente: Ana (_id: 10) é inserida, Bruno (_id: 20) é inserido. Quando chega em Caio (_id: 20), ocorre uma violação de chave primária duplicada. A execução é abortada imediatamente. Daniela (_id: 30) nunca chega a ser processada. A alternativa A está errada porque inserções em lote no MongoDB não rolam de volta (rollback) inserções passadas a menos que estejam explicitamente dentro de uma transação multi-documento ACID.

Questão 02:

Você precisa consultar a coleção pedidos e retornar apenas os campos cliente_id e total, sem incluir o campo _id original do MongoDB. Qual das opções abaixo executa essa tarefa corretamente sem gerar erros de sintaxe?

Alternativas:

A) db.pedidos.find({}, { cliente_id: 1, total: 1, _id: 0 });

B) db.pedidos.find({}, { cliente_id: 1, total: 1, status: 0 });

C) db.pedidos.find({ cliente_id: 1, total: 1 }, { _id: 0 });

D) db.pedidos.find({ projection: { cliente_id: true, total: true, _id: false } });

Ver Gabarito Comentado

Resposta Correta: A

Explicação: A alternativa A segue perfeitamente a exceção da regra de ouro das projeções: podemos especificar a inclusão de campos (cliente_id: 1, total: 1) e suprimir explicitamente o _id com _id: 0. A alternativa B tenta misturar inclusão (1) com exclusão (0) de um campo comum (status: 0), o que lança exceção no MongoDB. A alternativa C coloca a projeção no primeiro argumento (filtro de busca) incorretamente.

Questão 03:

Qual das seguintes consultas em mongosh encontra todos os documentos na coleção livros onde o campo preco é menor que 50 OU o campo esgotado NÃO existe?

Alternativas:

A) db.livros.find({ preco: { $lt: 50 }, esgotado: { $exists: false } });

B) db.livros.find({ $or: [ { preco: { $lt: 50 } }, { esgotado: { $exists: false } } ] });

C) db.livros.find({ $and: [ { preco: { $lt: 50 } }, { esgotado: { $type: "null" } } ] });

D) db.livros.find({ preco: { $lt: 50 } }).or({ esgotado: { $exists: false } });

Ver Gabarito Comentado

Resposta Correta: B

Explicação: O operador $or espera um array de sub-documentos de expressão. Para a condição "menor que 50 OU não existe", usamos { $or: [ { preco: { $lt: 50 } }, { esgotado: { $exists: false } } ] }. A alternativa A cria uma conjunção lógica E (AND) implícita entre as chaves do objeto JSON. A alternativa D utiliza uma sintaxe encadeada inexistente.

Prévia de Amanhã (Dia 03/15): Operações CRUD - Parte 2: Atualização e Remoção (update, delete, operadores $set, $unset, $inc, $push, $pull).

Bons estudos, dev! Conteúdo gerado especialmente para a sua preparação no MongoDB Associate Developer Exam.