Dia 03 de 15

Operações CRUD — Parte 2: Atualização & Remoção

Olá, dev! Seja bem-vindo ao Dia 03 da sua trilha para a certificação MongoDB Associate Developer. Hoje estudaremos minuciosamente as operações de modificação (Update) e exclusão (Delete) de documentos, com foco especial na atomicidade e no manuseio eficiente de coleções e arrays.

1. Métodos de Atualização: `updateOne()`, `updateMany()` e `replaceOne()`

No MongoDB, atualizações são divididas por escopo e intenção:

2. Operadores de Modificação de Campos

A. `$set` e `$unset`

O operador $set substitui o valor de um campo. Se o campo não existir, ele é criado automaticamente. O operador $unset remove completamente um campo do documento.

// Adiciona ou atualiza o campo cargo e remove o campo temporario
db.developers.updateOne(
  { email: "dev@exemplo.com" },
  {
    $set: { cargo: "Senior Backend Developer", nivel: "Pleno" },
    $unset: { campoTemporario: "" }
  }
)

B. `$inc`, `$mul`, `$min` e `$max`

// Incrementa tentativas em 1 e atualiza o maiorScore apenas se 950 for maior que o valor atual
db.developers.updateOne(
  { _id: ObjectId("64f8a12b9c3e2f1a8b4d5e6f") },
  {
    $inc: { "estatisticas.tentativasSimulado": 1 },
    $max: { "estatisticas.maiorScore": 950 }
  }
)

C. `$rename` e `$currentDate`

$rename altera o nome do campo. $currentDate define um campo para a data/hora atual (tipo Date ou Timestamp).

db.developers.updateOne(
  { email: "dev@exemplo.com" },
  {
    $rename: { "dataMatricula": "dataInscricao" },
    $currentDate: { ultimaAtualizacao: true }
  }
)

3. Manipulação Avançada de Arrays em Documentos

Arrays no MongoDB possuem operadores altamente otimizados para evitar a leitura e reescrita completa do documento no lado da aplicação.

A. `$push` com Modificadores (`$each`, `$slice`, `$sort`, `$position`)

O $push adiciona elementos ao final do array. Ao combinar com identificadores adicionais:

// Adiciona múltiplos itens, ordena em ordem decrescente e retém apenas os 5 maiores valores
db.developers.updateOne(
  { email: "dev@exemplo.com" },
  {
    $push: {
      notasSimulados: {
        $each: [92, 88, 96],
        $sort: -1,
        $slice: 5
      }
    }
  }
)

B. `$addToSet`, `$pop` e `$pull`

// Garante que a habilidade "Go" seja adicionada sem duplicatas e remove a habilidade descontinuada "Perl"
db.developers.updateOne(
  { email: "dev@exemplo.com" },
  {
    $addToSet: { habilidades: "Go" },
    $pull: { habilidades: "Perl" }
  }
)

C. Operador Posicional `$`

Permite atualizar o primeiro elemento do array que corresponda aos critérios de busca da consulta sem precisar saber o índice exato.

// Atualiza o status do curso "MongoDB Basics" para "Concluído"
db.developers.updateOne(
  { "cursos.nome": "MongoDB Basics" },
  { $set: { "cursos.$.status": "Concluído" } }
)

4. O Comportamento Upsert (`upsert: true`)

Quando a opção { upsert: true } é informada:

O Operador `$setOnInsert`

Define campos que devem ser gravados somente se a operação resultar em uma nova inserção (Upsert). Caso o documento já exista, o bloco $setOnInsert é ignorado.

db.developers.updateOne(
  { email: "novo.aluno@empresa.com" },
  {
    $set: { ativo: true },
    $setOnInsert: {
      dataCriacaoConta: new Date(),
      pontosIniciais: 100
    }
  },
  { upsert: true }
)

5. Operações de Remoção e Performance

Dica de Performance para o Exame:
Se o objetivo for apagar todos os documentos de uma coleção, utilizar db.collection.drop() é drasticamente mais rápido do que db.collection.deleteMany({}).
Isso ocorre porque deleteMany({}) remove os documentos um por um e atualiza os índices no arquivo do WiredTiger e gera logs no oplog, enquanto drop() simplesmente remove a coleção, suas tabelas no sistema de arquivos e todos os seus índices associados instantaneamente.

6. Questões no Estilo Exame de Certificação

Questão 1: Qual a combinação correta de modificadores com o operador $push para garantir que um array não ultrapasse o limite de 10 elementos mantendo apenas os mais recentes?

A) $push: { historico: { $each: [novoItem], $limit: 10 } }
B) $push: { historico: { $each: [novoItem], $slice: -10 } }
C) $push: { historico: { $each: [novoItem], $trim: 10 } }
D) $push: { historico: [novoItem], $slice: 10 }

Resposta Correta: B. O modificador $slice: -10 mantém apenas os últimos 10 elementos do array durante o $push com $each.

Questão 2: Um desenvolvedor deseja atualizar o campo ultimaVisualizacao de um documento se ele existir, mas caso o documento precise ser criado via upsert, ele quer também definir o campo dataCriacao. Qual operador atinge esse objetivo?

A) `$init`
B) `$setOnInsert`
C) `$onCreate`
D) `$upsertOnly`

Resposta Correta: B) `$setOnInsert`. Este operador especifica os valores que serão inseridos exclusivamente se o `upsert` criar um novo documento.