MongoDB: Excluindo documentos e primeiros passos com o…

Última atualização: 2026-08-26

A exclusão de documentos é uma operação fundamental na limpeza de dados — este curso também apresenta exercícios práticos com Node.js e Mongoose.

Domine as operações deleteOne/deleteMany, a integração entre Node.js e Mongoose, a definição de esquemas e as operações CRUD de modelos.

1. O que você vai aprender


2. A história real de um engenheiro full-stack

(1) Desafio: A limpeza de dados expirados exige scripts complexos

Bob precisa limpar regularmente os pedidos vencidos e as contas de usuário desativadas na plataforma de comércio eletrônico:

JAVASCRIPT
// ❌ Counterexample:Query multiple times, then delete(Slow + Race Condition)
const expiredOrders = await Order.find({ expiryDate: { $lt: new Date() } });
for (const order of expiredOrders) {
  await Order.deleteOne({ _id: order._id });
}
// N Sub-network round trip,N Second deletion operation

(2) Solução para exclusões em lote no MongoDB + Mongoose

JAVASCRIPT
// ✅ Correct Example:Bulk Deletion in One Go
const result = await Order.deleteMany({
  expiryDate: { $lt: new Date() }
});
// Delete all expired orders in a single operation

// mongoose Schema Definition
const OrderSchema = new mongoose.Schema({
  userId: { type: mongoose.Schema.Types.ObjectId, required: true },
  items: [{ sku: String, qty: Number, price: mongoose.Schema.Types.Decimal128 }],
  total: { type: mongoose.Schema.Types.Decimal128, required: true },
  status: { type: String, enum: ['pending', 'paid', 'shipped', 'delivered'], default: 'pending' },
  expiryDate: Date,
  createdAt: { type: Date, default: Date.now }
}, { timestamps: true });

const Order = mongoose.model('Order', OrderSchema);

100%
graph LR
    A[Delete Operation] --> B[deleteOne<br/>Delete a single item]
    A --> C[deleteMany<br/>Bulk Delete]
    A --> D[findOneAndDelete<br/>Atom Returns]
    A --> E[drop<br/>Delete Set]
    A --> F[dropDatabase<br/>Delete the database]

    style D fill:#d4edda

3. deleteOne: Excluir um único documento

Explicação do conceito: deleteOne Exclui o primeiro documento que atender aos critérios de filtragem; esse é o método de exclusão mais básico no MongoDB. A exclusão é irreversível — não há um mecanismo de “lixo eletrônico”, e os documentos excluídos não podem ser restaurados diretamente (a menos que haja um backup ou um oplog disponível). Portanto, as operações de exclusão devem ser realizadas com extrema cautela em ambientes de produção.

Como funciona: deleteOne O fluxo de execução é o seguinte: Fase de correspondência (localizar o primeiro documento com base no filtro) → Fase de exclusão (remover o documento da coleção) → Atualização do índice (excluir as entradas relevantes do índice) → Confirmação da Write Concern. Toda a operação é atômica para um único documento. Após a exclusão, o espaço em disco não é liberado imediatamente, mas é marcado como espaço reutilizável.

100%
sequenceDiagram
    participant App as Applications
    participant Mongo as MongoDB
    participant WT as WiredTiger

    App->>Mongo: deleteOne({ sku: "PHONE-001" })
    Mongo->>Mongo: Match filter (Index Scan)
    Mongo->>WT: Delete Document + Update Index
    WT-->>Mongo: Confirm Deletion
    Mongo-->>App: { acknowledged: true, deletedCount: 1 }
Parâmetro Tipo Descrição
filter Documento Critérios de pesquisa (obrigatórios)
options Documento writeConcern etc. (opcional)
Campo de retorno Tipo Descrição
acknowledged Booleano Se a gravação foi confirmada
deletedCount Número Número de documentos excluídos (0 ou 1)
JAVASCRIPT
// === deleteOne Basic Usage ===
db.products.deleteOne({ sku: 'PHONE-001' });

// Return Results:
// { acknowledged: true, deletedCount: 1 }
Campo de retorno Significado
acknowledged Isso já foi confirmado?
deletedCount Número de documentos excluídos (0 ou 1)

▶ Exemplo 1: deleteOne em ação

JAVASCRIPT
// === Delete Specified _id the document ===
db.users.deleteOne({ _id: ObjectId('507f1f77bcf86cd799439011') });

// === Delete Based on Specified Criteria(First match)===
db.logs.deleteOne({ level: 'debug' });

// === mongoose Equivalent ===
const result = await Product.deleteOne({ sku: 'PHONE-001' });
console.log(result.deletedCount);  // 1

4. deleteMany: Exclusão em lote

Descrição do conceito: deleteMany exclui todos os documentos que atendem aos critérios de filtragem e é o método principal para a limpeza em lote de dados. Ao contrário do deleteOne, que exclui apenas o primeiro documento correspondente, o deleteMany pode excluir dezenas de milhares de documentos de uma só vez. Casos de uso comuns incluem a limpeza de registros expirados, a exclusão de dados de usuários desativados e a remoção de dados de teste.

Como funciona: deleteMany Primeiro, ele recupera todos os documentos correspondentes e, em seguida, os exclui um por um. O processo de exclusão não é transacional — se falhar no meio do caminho, os documentos que já tiverem sido excluídos não serão restaurados. Para exclusões em massa, recomenda-se executá-las em lotes para evitar o bloqueio da coleção por um período prolongado.

Dimensão deleteOne deleteMany
Intervalo de partidas Primeira partida Todas as partidas
Número de exclusões 0 ou 1 0 a N
Casos de uso Excluir um único item Limpeza em massa
Risco Baixo Moderado (impacto significativo devido a erro do usuário)
JAVASCRIPT
// === deleteMany Basic Usage ===
db.products.deleteMany({ category: 'Discontinued' });

// === Delete all expired orders ===
db.orders.deleteMany({
  expiryDate: { $lt: new Date() }
});

// === Delete Multiple Documents That Meet Specific Criteria ===
db.logs.deleteMany({
  level: { $in: ['debug', 'info'] },
  createdAt: { $lt: new Date(Date.now() - 30 * 24 * 60 * 60 * 1000) }
});

▶ Exemplo 2: deleteMany na prática

JAVASCRIPT
// === Cleanup 30 Entries from a few days ago ===
const thirtyDaysAgo = new Date(Date.now() - 30 * 24 * 60 * 60 * 1000);
const result = await Log.deleteMany({ createdAt: { $lt: thirtyDaysAgo } });
console.log(`Deleted ${result.deletedCount} old logs`);

// === Delete the session of a logged-out user ===
await Session.deleteMany({ userId: deletedUserId });

// === Delete all documents from the entire collection(Use with caution!)===
db.products.deleteMany({});
// ⚠️ This will delete products All documents in the collection

5. Retorno atômico do findOneAndDelete

Descrição do conceito: findOneAndDelete é um método especial de exclusão que retorna o conteúdo do documento excluído ao mesmo tempo em que o exclui. Isso resolve a condição de corrida associada à abordagem “primeiro consultar, depois excluir” — a abordagem tradicional exige primeiro findOne recuperar o documento e, em seguida, deleteOne excluí-lo, período durante o qual o documento pode ser modificado ou excluído por outras operações. findOneAndDelete combina a consulta e a exclusão em uma única operação atômica.

Como funciona: findOneAndDelete realiza uma operação atômica no nível do documento: localiza o documento correspondente → registra o conteúdo do documento → exclui o documento → retorna o conteúdo registrado. Por padrão, retorna o estado do documento antes da exclusão; a opção projection pode ser usada para controlar quais campos são retornados.

100%
graph TB
    A[Need to delete and retrieve a document] --> B{Method Selection}
    B --> C[❌ Check First, Then Delete<br/>findOne + deleteOne<br/>Competitive Conditions Risk]
    B --> D[✅ findOneAndDelete<br/>Atomic Manipulation<br/>No risk of competition]
    B --> E[✅ findOneAndDelete + sort<br/>Atomic Manipulation + Order<br/>FIFO Queue]

    style D fill:#d4edda
    style E fill:#d4edda
Vantagem Descrição
Atomicidade A consulta e a exclusão são realizadas em uma única operação, evitando condições de corrida
Recuperar documento Recuperar diretamente o documento excluído, sem a necessidade de uma consulta secundária
Suporte à ordenação Permite o consumo ordenado quando usado com a opção sort
Casos de uso Enfileiramento de tarefas, consumo de mensagens, dedução de estoque
JAVASCRIPT
// === findOneAndDelete Atomic Manipulation ===
const deletedDoc = db.products.findOneAndDelete({ sku: 'PHONE-001' });

// Restore Deleted Documents(Status before default deletion)
console.log(deletedDoc);
// { _id: ..., sku: 'PHONE-001', title: 'Phone', price: 599, ... }

// === Return if it does not exist null ===
const result = db.products.findOneAndDelete({ sku: 'NOT_EXIST' });
console.log(result);  // null
Vantagem Descrição
Atomicidade A consulta e a exclusão são realizadas em uma única operação, evitando condições de corrida
Recuperar documento Recuperar diretamente o documento excluído, sem a necessidade de uma consulta secundária
Casos de uso Enfileiramento de tarefas, consumo de mensagens, dedução de estoque

▶ Exemplo 3: findOneAndDelete em ação

JAVASCRIPT
// === Scene:Message Queue(FIFO)===
const message = await Queue.findOneAndDelete(
  { status: 'pending' },
  { sort: { createdAt: 1 } }  // Consume the oldest ones first
);

// === Scene:Claim a Mission ===
const task = await Task.findOneAndDelete({
  status: 'available',
  assignee: null
});
if (task) {
  console.log(`Claimed task: ${task._id}`);
}

// === mongoose Equivalent ===
const message = await Queue.findOneAndDelete(
  { status: 'pending' },
  { sort: { createdAt: 1 } }
);

6. drop Collection e dropDatabase

Explicação conceitual: drop e dropDatabase são as operações de exclusão mais completas — drop exclui uma coleção inteira (incluindo todos os documentos e índices), e dropDatabase exclui todo o banco de dados (incluindo todas as coleções). Ao contrário de deleteMany({}), a operação drop não apenas exclui os dados, mas também exclui os metadados da coleção (definições de índice, regras de validação de esquema, configurações de limite, etc.).

Análise comparativa:

Dimensão deleteMany({}) drop() dropDatabase()
Escopo da exclusão Todos os documentos da coleção A coleção inteira O banco de dados inteiro
Manter índice ✅ Manter ❌ Excluir tudo ❌ Excluir tudo
Manter a configuração “capped” ✅ Manter ❌ Excluir ❌ Excluir
Manter a validação do esquema ✅ Manter ❌ Excluir ❌ Excluir
Velocidade Lenta (exclui um por um) Rápida (libera espaço imediatamente) Rápida
Recuperabilidade Pode ser recuperado por meio do oplog Extremamente difícil de recuperar Extremamente difícil de recuperar
JAVASCRIPT
// === Delete Set ===
db.products.drop();
// true(Success)or false(The set does not exist)

// === Delete the database ===
db.dropDatabase();
// { "dropped" : "shopdb", "ok" : 1 }

// === Use with caution: Delete all data from the entire collection but keep the collection itself ===
db.products.deleteMany({});
// Equivalent but preserves the set structure(Index、capped Settings)

▶ Exemplo 4: Escolhendo entre drop e deleteMany

JAVASCRIPT
// Scene:Cleaning Up Temporary Test Sets
// ✅ Recommendations:drop(Delete Set+Index,Clean)
db.test_results.drop();

// ✅ Preserve the collection structure:deleteMany(Clear the document only)
db.user_sessions.deleteMany({});

7. Node.js + Mongoose: Conectando-se ao MongoDB

Visão geral do conceito: O Mongoose é o ODM (Modelagem de Objetos e Documentos) do MongoDB mais popular no ecossistema Node.js, oferecendo recursos avançados, como definição de esquema, validação de dados, middleware e consultas com junção. Esta seção começa com a conexão ao MongoDB e apresenta, gradualmente, os conceitos fundamentais do Mongoose.

Como funciona: O processo pelo qual o Mongoose se conecta ao MongoDB consiste nas seguintes etapas: criação de uma instância de conexão → estabelecimento de uma conexão TCP → autenticação (se necessário) → seleção de um banco de dados → inicialização do pool de conexões → acionamento do evento connected. Por padrão, o Mongoose mantém um pool de conexões (normalmente de 5 a 100 conexões) e reutiliza as conexões para evitar o estabelecimento e o fechamento frequentes de conexões TCP.

100%
sequenceDiagram
    participant App as Node.js Applications
    participant Mongoose as mongoose
    participant Mongo as MongoDB

    App->>Mongoose: mongoose.connect(uri)
    Mongoose->>Mongo: Establish TCP Connect
    Mongo-->>Mongoose: Connection Confirmation
    Mongoose->>Mongo: Certification(If you need)
    Mongo-->>Mongoose: Authentication Successful
    Mongoose->>Mongoose: Initialize the connection pool
    Mongoose-->>App: Trigger 'connected' Event
    Note over App,Mongoose: Connection Ready,Executable CRUD
Método de conexão Formato da URI Casos de uso
Autônomo local mongodb://localhost:27017/shopdb Ambiente de desenvolvimento
Atlas Cloud mongodb+srv://user:pass@cluster0.mongodb.net/mydb Produção/Equipe
Conjunto de instâncias mongodb://host1,host2,host3/shopdb?replicaSet=rs0 Ambiente de produção
Docker mongodb://192.168.1.100:27017/shopdb Implantação em contêineres

(1) Instalar o Mongoose

BASH
npm install mongoose --save

(2) Conectando-se ao MongoDB

JAVASCRIPT
// === Basic Connections ===
const mongoose = require('mongoose');

async function connectDB() {
  await mongoose.connect('mongodb://localhost:27017/shopdb');
  console.log('✅ MongoDB connected');
}

connectDB().catch(err => console.error('❌ Connection error:', err));

(3) Opções de conexão

Explicação do conceito: As opções de conexão do Mongoose controlam parâmetros-chave que determinam o comportamento da conexão — como tempo limite, tamanho do pool de conexões e métodos de autenticação. Essas opções devem ser configuradas adequadamente em ambientes de produção; caso contrário, podem resultar em vazamentos de conexão, falhas por tempo limite ou erros de autenticação.

Descrições dos parâmetros principais:

Parâmetro Valor padrão Descrição Recomendação para produção
serverSelectionTimeoutMS 30000 Tempo limite para seleção do servidor (milissegundos) 5000
socketTimeoutMS 30.000 Tempo limite do soquete 45.000
maxPoolSize 100 Tamanho máximo do pool de conexões 50–100
minPoolSize 0 Tamanho mínimo do pool de conexões 5
heartbeatFrequencyMS 10.000 Frequência de monitoramento da frequência cardíaca 10.000
retryWrites true Nova tentativa automática de gravação true
authSource admin Banco de dados de autenticação Conforme configurado

Princípio do pool de conexões: O Mongoose mantém um pool de conexões TCP para evitar a sobrecarga causada pela criação e destruição frequentes de conexões. Cada solicitação simultânea retira uma conexão do pool e a devolve assim que a solicitação é concluída. maxPoolSize Controle o número máximo de conexões simultâneas — definir esse valor muito baixo fará com que as solicitações fiquem em fila, enquanto defini-lo muito alto consumirá recursos excessivos do servidor.

JAVASCRIPT
// === Complete Connection Configuration ===
await mongoose.connect('mongodb://localhost:27017/shopdb', {
  // Server selection timeout
  serverSelectionTimeoutMS: 5000,

  // Socket Timeout
  socketTimeoutMS: 45000,

  // Connection Pool Size
  maxPoolSize: 50,
  minPoolSize: 5,

  // Automatic Reconnection
  autoReconnect: true,

  // Certification(If enabled)
  user: 'admin',
  pass: 'password',

  // Certification Database
  authSource: 'admin'
});

(4) Conecte-se ao Atlas

JAVASCRIPT
// === Atlas Concatenate Strings ===
await mongoose.connect(
  'mongodb+srv://user:pass@cluster0.mongodb.net/mydb?retryWrites=true&w=majority'
);

// === With environment variables ===
require('dotenv').config();
await mongoose.connect(process.env.MONGODB_URI);

▶ Exemplo 5: Gerenciamento completo de conexões

JAVASCRIPT
// db.js
const mongoose = require('mongoose');

const connectDB = async () => {
  try {
    const conn = await mongoose.connect(process.env.MONGODB_URI || 'mongodb://localhost:27017/shopdb', {
      serverSelectionTimeoutMS: 5000,
      maxPoolSize: 50
    });
    console.log(`✅ MongoDB connected: ${conn.connection.host}`);

    // Listening for Connection Events
    mongoose.connection.on('error', (err) => console.error('❌ MongoDB error:', err));
    mongoose.connection.on('disconnected', () => console.warn('⚠️ MongoDB disconnected'));
    mongoose.connection.on('reconnected', () => console.log('🔄 MongoDB reconnected'));
  } catch (err) {
    console.error('❌ Connection failed:', err.message);
    process.exit(1);
  }
};

const disconnectDB = async () => {
  await mongoose.disconnect();
  console.log('MongoDB disconnected');
};

module.exports = { connectDB, disconnectDB, mongoose };

8. Definição do esquema do Mongoose

Explicação do conceito: Um esquema é um conceito fundamental no Mongoose — ele define os tipos de campo de um documento, as regras de validação, os valores padrão, os índices e muito mais. Embora o próprio MongoDB seja sem esquema, o Mongoose oferece restrições de esquema na camada de aplicação para evitar dados incorretos e erros de tipo. Uma vez definido, um esquema é compilado em um modelo, que serve como interface para interagir com o banco de dados.

Como funciona: Esquema → Modelo → Documento é a arquitetura de três camadas do Mongoose. O Esquema define a estrutura (tipos de campos e validação); o Modelo é o resultado compilado do Esquema (correspondente a uma coleção); e o Documento é uma instância do Modelo (correspondente a um documento). O Esquema não interage diretamente com o banco de dados; as operações CRUD só podem ser realizadas por meio do Modelo.

Opções do Schema: O segundo parâmetro do construtor do Schema controla o comportamento global — timestamps: true adiciona automaticamente createdAt/updatedAt, strict: true ignora campos não declarados e versionKey: false remove a chave de versão __v.

100%
graph LR
    A[Schema<br/>Define Field Types+Verification] -->|mongoose.model| B[Model<br/>Interfaces for Operation Sets]
    B -->|new Model| C[Document<br/>An Example Document]
    B -->|Model.find| D[Search Results<br/>Document Array]

    style A fill:#cce5ff
    style B fill:#d4edda
Opções de campos do esquema Tipo Descrição Exemplo
type Construtor Tipo de campo String, Number, Date
required Booleano/Matriz Obrigatório [true, 'Email is required']
default Qualquer/Função Valor padrão Date.now, 0, true
unique Booleano Se deve ser criado um índice único true
index Booleano/Objeto Criar índice true, { sparse: true }
enum Matriz Lista de valores permitidos ['pending', 'paid']
min / max Número Intervalo de valores min: 0, max: 999999
minlength / maxlength Número Intervalo de comprimento da sequência minlength: 3
match RegExp Validação de expressões regulares /^.+@.+$/
select Booleano Se a consulta padrão retorna false (por exemplo, passwordHash)
validate Função Função de validação personalizada v => v.length >= 8
get / set Função Getter/setter virtual get: v => v.toString()

(1) Esquema básico

JAVASCRIPT
// === Schema Defining the User Model ===
const UserSchema = new mongoose.Schema({
  // Field Definitions
  email: {
    type: String,
    required: true,
    unique: true,
    lowercase: true,
    trim: true
  },
  username: {
    type: String,
    required: true,
    unique: true,
    minlength: 3,
    maxlength: 30
  },
  passwordHash: {
    type: String,
    required: true,
    select: false  // The default query returns no results.
  },
  age: {
    type: Number,
    min: 0,
    max: 150
  },
  role: {
    type: String,
    enum: ['customer', 'admin', 'moderator'],
    default: 'customer'
  },
  isActive: {
    type: Boolean,
    default: true
  }
}, {
  // Schema Options
  timestamps: true,           // Auto-add createdAt/updatedAt
  collection: 'users',       // Explicitly Specify the Set Name
  strict: true,              // Strict Mode(Do not save undeclared fields)
  versionKey: false          // Disable __v
});

(2) Tipos de esquema

JAVASCRIPT
const ProductSchema = new mongoose.Schema({
  // String
  sku: String,

  // Numbers
  stock: Number,
  price: mongoose.Schema.Types.Decimal128,

  // Date
  releaseDate: Date,

  // Boolean
  isActive: Boolean,

  // Array
  tags: [String],

  // Nested Documents
  specs: {
    screen: String,
    battery: String
  },

  // Buffer(Binary)
  thumbnail: Buffer,

  // ObjectId Quote
  categoryId: mongoose.Schema.Types.ObjectId,

  // Mixed Type(Any)
  metadata: mongoose.Schema.Types.Mixed,

  // Map(Key-value pairs)
  translations: {
    type: Map,
    of: String
  }
});

▶ Exemplo 6: Projeto abrangente de esquema

JAVASCRIPT
const ProductSchema = new mongoose.Schema({
  sku: {
    type: String,
    required: [true, 'SKU is required'],
    unique: true,
    index: true,
    match: /^[A-Z0-9-]+$/
  },
  title: {
    type: String,
    required: true,
    trim: true,
    maxlength: 200
  },
  description: {
    type: String,
    maxlength: 5000
  },
  price: {
    type: mongoose.Schema.Types.Decimal128,
    required: true,
    min: 0,
    get: v => v ? v.toString() : v  // Serialize to a string
  },
  category: {
    type: String,
    enum: ['Electronics', 'Books', 'Clothing', 'Home'],
    required: true,
    index: true
  },
  tags: [String],
  attributes: {
    type: Map,
    of: mongoose.Schema.Types.Mixed,
    default: {}
  },
  stock: {
    type: Number,
    default: 0,
    min: 0
  },
  rating: {
    type: Number,
    default: 0,
    min: 0,
    max: 5
  },
  isActive: {
    type: Boolean,
    default: true,
    index: true
  }
}, {
  timestamps: true,
  toJSON: { virtuals: true, getters: true },
  toObject: { virtuals: true }
});

// Virtual Fields
ProductSchema.virtual('isInStock').get(function() {
  return this.stock > 0;
});

// Index
ProductSchema.index({ category: 1, price: 1 });
ProductSchema.index({ title: 'text', description: 'text' });

const Product = mongoose.model('Product', ProductSchema);

9. Operações CRUD no Mongoose

Explicação do conceito: CRUD (Criar/Ler/Atualizar/Excluir) é o padrão básico para operações em bancos de dados. O Mongoose oferece dois estilos de CRUD — métodos estáticos do modelo (como Model.create() e Model.find()) e métodos de instância do documento (como doc.save() e doc.remove()). Os métodos estáticos operam diretamente no banco de dados, enquanto os métodos de instância primeiro modificam o objeto na memória e, em seguida, sincronizam as alterações com o banco de dados.

Análise comparativa:

Dimensão Métodos estáticos do modelo Métodos de instância do documento
Método de chamada Model.create(data) new Model(data); doc.save()
Verificação do gatilho
Middleware acionado Parcial ✅ Todos
Valor de retorno Documento ou objeto de resultado Documento
Casos de uso CRUD simples Lógica de negócios complexa
100%
graph TB
    A[mongoose CRUD] --> B[Create<br/>create() / save()]
    A --> C[Read<br/>find() / findOne() / findById()]
    A --> D[Update<br/>updateOne() / findByIdAndUpdate()]
    A --> E[Delete<br/>deleteOne() / findByIdAndDelete()]

    style A fill:#cce5ff

(1) Criar

JAVASCRIPT
// === model.create() Create a Single Document ===
const user = await User.create({
  email: 'alice@example.com',
  username: 'alice_chen',
  passwordHash: 'hashed_password',
  age: 28
});
console.log(user._id);  // ObjectId

// === Create Multiple Documents ===
const users = await User.create([
  { email: 'bob@example.com', username: 'bob' },
  { email: 'charlie@example.com', username: 'charlie' }
]);

// === new + save Pattern ===
const user = new User({
  email: 'alice@example.com',
  username: 'alice_chen'
});
await user.save();

(2) Ler

JAVASCRIPT
// === find Search for multiple ===
const users = await User.find({ isActive: true });

// === findOne Query a single ===
const user = await User.findOne({ email: 'alice@example.com' });

// === findById Through _id Search ===
const user = await User.findById('507f1f77bcf86cd799439011');

// === Chain Query ===
const products = await Product.find({ category: 'Electronics' })
  .select('sku title price')
  .sort({ price: 1 })
  .limit(20)
  .lean();

(3) Atualização

JAVASCRIPT
// === findByIdAndUpdate ===
const user = await User.findByIdAndUpdate(
  userId,
  { $set: { lastLoginAt: new Date() } },
  { new: true, runValidators: true }  // Return to the updated document
);

// === updateOne ===
const result = await User.updateOne(
  { email: 'alice@example.com' },
  { $set: { age: 29 } }
);

// === save() Replace the entire document ===
const user = await User.findById(userId);
user.age = 30;
await user.save();

(4) Excluir

JAVASCRIPT
// === findByIdAndDelete ===
const user = await User.findByIdAndDelete(userId);

// === deleteOne ===
const result = await User.deleteOne({ email: 'alice@example.com' });

// === deleteMany ===
const result = await User.deleteMany({ isActive: false });

▶ Exemplo 7: Um exercício prático completo de CRUD

JAVASCRIPT
// === 1. Create a User ===
const alice = await User.create({
  email: 'alice@example.com',
  username: 'alice_chen',
  passwordHash: await bcrypt.hash('password123', 10),
  age: 28
});

// === 2. Query User ===
const users = await User.find({ age: { $gte: 18 } })
  .select('email username age')
  .lean();

// === 3. Update User ===
await User.updateOne(
  { _id: alice._id },
  { $set: { lastLoginAt: new Date() }, $inc: { loginCount: 1 } }
);

// === 4. Delete Test User ===
await User.deleteMany({ email: { $regex: '@test\\.com$' } });

10. Resolução de erros comuns

Visão geral do conceito: Os quatro tipos mais comuns de erros encontrados ao desenvolver com Node.js e Mongoose são: erros de conexão (ECONNREFUSED), conflitos de índice único (E11000), falhas na validação do esquema (ValidationError) e falhas na conversão de tipos (CastError). Compreender as causas fundamentais desses erros e saber como lidar com eles é uma habilidade essencial no desenvolvimento com Mongoose.

Estratégia de tratamento de erros: Erros de conexão exigem um mecanismo de repetição da tentativa; conflitos de índices únicos exigem um UPSERT ou validação no front-end; falhas na validação do esquema exigem uma validação aprimorada dos formulários; e erros de conversão (CastErrors) exigem a verificação do formato do ObjectId. Todos os erros devem ser interceptados na camada de aplicação e retornar mensagens de erro fáceis de entender — não exponha o rastreamento da pilha de erros bruto do MongoDB aos usuários do front-end.

100%
graph TB
    A[mongoose Error] --> B[Connection Error<br/>ECONNREFUSED]
    A --> C[Unique Index Conflict<br/>E11000]
    A --> D[Verification Failed<br/>ValidationError]
    A --> E[Type conversion failed<br/>CastError]
    
    B --> B1[Inspection mongod Enable or Disable<br/>Check the connection string]
    C --> C1[Usage upsert<br/>Front-End Uniqueness Validation]
    D --> D1[Improve Schema Verification<br/>Front-End Form Validation]
    E --> E1[Inspection ObjectId Format<br/>Verify Parameter Types]
Erro Causa Solução
MongooseServerSelectionError: connect ECONNREFUSED O MongoDB não está em execução brew services start mongodb-community@7.0
MongoError: E11000 duplicate key error Conflito de índice exclusivo Verificar se há valores duplicados nos campos
ValidationError: Path 'email' is required Faltam campos obrigatórios Preencha os campos obrigatórios
CastError: Cast to ObjectId failed Erro de formato do _id Verifique o formato da string do ObjectId

❓ Perguntas Frequentes

P: O que é melhor, deleteOne ou findOneAndDelete? R: Use findOneAndDelete se precisar recuperar o documento excluído; use deleteOne se quiser apenas excluí-lo. Ambos apresentam desempenho comparável.

P: É necessário fechar as conexões do Mongoose? R: Sim. Chame mongoose.disconnect() ou mongoose.connection.close() quando o processo for encerrado para garantir que todas as conexões sejam fechadas corretamente.

P: Se um campo for alterado no esquema, é necessário migrar o banco de dados? R: Não. O esquema do Mongoose é definido na camada de aplicação e não afeta o banco de dados. O MongoDB não possui esquema, portanto, novos campos são adicionados automaticamente. No entanto, os documentos antigos podem não conter os novos campos, de modo que a camada de aplicação deve lidar com essa situação undefined.

P: Qual é o impacto no desempenho do lean()? R: O lean() ignora a hidratação de documentos do Mongoose e retorna um objeto JavaScript puro. Isso resulta em um aumento de desempenho de 3 a 5 vezes, mas você perde o acesso aos métodos de documentos do Mongoose (como save() e populate()). É adequado para APIs de consulta puras.

P: Qual é a diferença entre Model.create e new Model + save? R: Ambos acionam a validação do esquema e o middleware. A sintaxe Model.create() é mais concisa, enquanto new + save é mais adequada para cenários que exigem operações passo a passo.


📖 Resumo


📝 Exercícios

  1. Pergunta básica (⭐): Use deleteOne para excluir o produto com o SKU 'TEST-001'.
  2. Questões básicas (⭐): Defina o modelo Product usando o Mongoose Schema (incluindo sku, title, price, category e stock) e execute as operações create, find, update e delete.
  3. Problema avançado (⭐⭐): Escreva um script em Node.js para limpar periodicamente os pedidos vencidos com mais de 30 dias (usando deleteMany).
  4. Problema avançado (⭐⭐): Implemente uma fila de mensagens: use findOneAndDelete com sort: { createdAt: 1 } para implementar o consumo FIFO.
  5. Desafio (⭐⭐⭐): Implemente um recurso de cadastro de usuários usando Mongoose, Schema e middleware (incluindo validação da exclusividade do e-mail, hash de senha com bcrypt e registro de data e hora).
Web-Tutorial.com

Equipe Técnica Web-Tutorial

Uma plataforma de tutoriais mantida por diversos desenvolvedores. Cada tutorial é escrito e revisado por profissionais da área correspondente. Trabalhamos para manter nosso conteúdo preciso e confiável — se encontrar algum problema, avise-nos.

100%