Node.js: MongoDB com Node.js

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

1. Por que escolher o MongoDB

A API de comércio eletrônico da Alice enfrenta um problema complicado: os atributos dos produtos variam muito entre as diferentes categorias — os laptops têm campos de CPU e memória, as roupas têm campos de tamanho e cor, e os alimentos têm campos de data de validade. Se fosse utilizado um banco de dados relacional, a estrutura da tabela teria que ser modificada toda vez que uma nova categoria fosse adicionada. O modelo de documentos do MongoDB suporta naturalmente registros com estruturas diferentes; cada documento de produto pode ter campos completamente diferentes, sem a necessidade de qualquer migração de esquema.

Conceitos de SQL Conceitos do MongoDB Descrição
Banco de dados Banco de dados Banco de dados, terminologia consistente
Tabela Coleção Tabela → Coleção
Linha Documento Linha → Documento
Coluna Campo Coluna → Campo
Chave primária _id (ObjectId) Chave primária gerada automaticamente
JOIN $lookup (Agregação) Diferentes tipos de consultas de junção
Esquema Sem esquema obrigatório Regra de validação opcional
Índice Índice Mecanismos de indexação semelhantes


2. Instalação e conexão

(1) Instale o driver do MongoDB

Use o pacote oficial mongodb do npm para se conectar a um servidor MongoDB.

▶ Exemplo: Instalação de um driver

BASH
npm install mongodb

(2) Estabelecer uma conexão com o cliente

MongoClient é o ponto de entrada para se conectar ao MongoDB; ele especifica o endereço e as opções por meio de uma string de conexão.

▶ Exemplo: Conexão básica

JAVASCRIPT
const { MongoClient } = require('mongodb');

const uri = 'mongodb://localhost:27017';
const client = new MongoClient(uri);

async function connect() {
  try {
    await client.connect();
    console.log('Connected to MongoDB');
    const db = client.db('myapp');
    return db;
  } catch (err) {
    console.error('Connection failed:', err.message);
    process.exit(1);
  }
}
▶ Experimente

(3) Pools de conexão e opções de configuração

MongoClient Pool de conexões integrado; o tamanho e o comportamento do pool são controlados por meio de opções.

▶ Exemplo: Conexão com configuração de pool de conexões

JAVASCRIPT
const client = new MongoClient(uri, {
  maxPoolSize: 10,
  minPoolSize: 2,
  maxIdleTimeMS: 30000,
  serverSelectionTimeoutMS: 5000,
  connectTimeoutMS: 10000,
});
▶ Experimente
Opção de configuração Valor padrão Descrição
maxPoolSize 100 Número máximo de conexões no pool de conexões
minPoolSize 0 Número mínimo de conexões no pool de conexões
maxIdleTimeMS 0 Tempo limite de conexão inativa (0 = sem tempo limite)
serverSelectionTimeoutMS 30000 Tempo limite para seleção do servidor expirou
connectTimeoutMS 30000 Tempo limite para o estabelecimento da conexão expirou
socketTimeoutMS 0 Tempo limite do soquete
retryWrites true Repetir automaticamente as operações de gravação

(4) Encerramento adequado das conexões

Quando o aplicativo for encerrado, ele deve fechar as conexões e liberar os recursos.

▶ Exemplo: Desligamento controlado

JAVASCRIPT
process.on('SIGINT', async () => {
  await client.close();
  console.log('MongoDB connection closed');
  process.exit(0);
});
▶ Experimente

3. Operações CRUD

(1) Inserir um documento

Use insertOne para inserir um único documento e insertMany para inserir vários documentos.

▶ Exemplo: Inserção da documentação do produto

JAVASCRIPT
const products = db.collection('products');

const result = await products.insertOne({
  name: 'Mechanical Keyboard',
  price: 89.99,
  category: 'electronics',
  specs: { switches: 'Cherry MX Blue', layout: 'ANSI' },
  createdAt: new Date(),
});

console.log('Inserted ID:', result.insertedId);
▶ Experimente

(2) Pesquise na documentação

find Retorna o cursor; findOne retorna um único documento.

▶ Exemplo: Consulta de produtos

JAVASCRIPT
const product = await products.findOne({ category: 'electronics' });
console.log(product);

const cursor = products.find({ price: { $gt: 50 } });
const expensive = await cursor.toArray();
console.log(`${expensive.length} products found`);
▶ Experimente

(3) Atualizar a documentação

updateOne Atualiza a primeira correspondência; updateMany atualiza todas as correspondências.

▶ Exemplo: Atualização dos preços dos produtos

JAVASCRIPT
const updateResult = await products.updateOne(
  { name: 'Mechanical Keyboard' },
  { $set: { price: 79.99, updatedAt: new Date() } },
);

console.log('Modified count:', updateResult.modifiedCount);
▶ Experimente

(4) Excluir um documento

deleteOne exclui a primeira ocorrência; deleteMany exclui todas as ocorrências.

▶ Exemplo: Exclusão de um produto

JAVASCRIPT
const deleteResult = await products.deleteOne({
  name: 'Mechanical Keyboard',
});

console.log('Deleted count:', deleteResult.deletedCount);
▶ Experimente

(5) Referência rápida aos métodos CRUD

Operação Método Valor de retorno Descrição
Inserir um único registro insertOne(doc) {insertedId} Retornar o ID gerado automaticamente
Inserir vários insertMany([doc]) {insertedIds, insertedCount} Inserção em lote
Consultar um único registro findOne(filter) Documento ou nulo Retornar a primeira correspondência
Consultar várias linhas find(filter) Cursor Requer toArray() ou iteração
Atualizar uma única entrada updateOne(filter, update) {modifiedCount} Atualizar apenas a primeira entrada
Atualizar várias entradas updateMany(filter, update) {modifiedCount} Atualizar todas as correspondências
Excluir uma única entrada deleteOne(filter) {deletedCount} Excluir a primeira ocorrência
Excluir vários deleteMany(filter) {deletedCount} Excluir todas as ocorrências
Substituir no documento replaceOne(filter, doc) {modifiedCount} Substituir em todo o documento


4. ObjectId e operadores de consulta

(1) O mecanismo ObjectId

O valor padrão _id para cada documento é do tipo ObjectId; a codificação de 12 bytes inclui um carimbo de data e hora, um identificador da máquina e um contador.

▶ Exemplo: Como usar o ObjectId

JAVASCRIPT
const { ObjectId } = require('mongodb');

const id = new ObjectId();
console.log('ID string:', id.toHexString());
console.log('Timestamp:', id.getTimestamp());

const product = await products.findOne({
  _id: new ObjectId('6850a1b2c3d4e5f6a7b8c9d0'),
});
▶ Experimente

(2) Operadores de comparação

▶ Exemplo: Consulta de comparação

JAVASCRIPT
const expensive = await products.find({ price: { $gt: 100 } }).toArray();
const cheap = await products.find({ price: { $lt: 20 } }).toArray();
const midRange = await products.find({ price: { $gte: 50, $lte: 100 } }).toArray();
▶ Experimente

(3) Operadores lógicos e de conjuntos

▶ Exemplo: consultas com $in e $or

JAVASCRIPT
const selected = await products.find({
  category: { $in: ['electronics', 'books'] },
}).toArray();

const mixed = await products.find({
  $or: [
    { price: { $lt: 10 } },
    { category: 'electronics' },
  ],
}).toArray();
▶ Experimente

(4) Consultas com expressões regulares

▶ Exemplo: Expressão regular para identificar nomes de produtos

JAVASCRIPT
const matched = await products.find({
  name: { $regex: /^Mechanical/i },
}).toArray();
▶ Experimente

(5) Referência rápida para operadores de consulta

Operador Sintaxe Descrição
$eq {field: {$eq: val}} é igual a (e {field: val})
$gt {field: {$gt: val}} Maior que
$gte {field: {$gte: val}} Maior ou igual a
$lt {field: {$lt: val}} menor que
$lte {field: {$lte: val}} Menor ou igual a
$ne {field: {$ne: val}} Não é igual a
$in {field: {$in: [v1,v2]}} Dentro da matriz
$nin {field: {$nin: [v1,v2]}} Não consta na matriz
$or {$or: [{...},{...}]} ou condição
$and {$and: [{...},{...}]} Condições
$not {field: {$not: {...}}} Desmarcar
$regex {field: {$regex: 'pattern'}} Correspondência de expressão regular
$exists {field: {$exists: true}} Esse campo existe?


5. Projeção e classificação

(1) Campo de retorno do controle de projeção

A projeção especifica quais campos devem ser retornados ou excluídos, reduzindo assim o tráfego de rede.

▶ Exemplo: Consulta de projeção

JAVASCRIPT
const names = await products.find(
  {},
  { projection: { name: 1, price: 1, _id: 0 } },
).toArray();

const withoutSpecs = await products.find(
  {},
  { projection: { specs: 0, createdAt: 0 } },
).toArray();
▶ Experimente

(2) Ordenação e paginação

sort ordena os resultados, enquanto skip e limit implementam a paginação.

▶ Exemplo: Ordenação e paginação

JAVASCRIPT
const page = 2;
const pageSize = 10;

const sorted = await products.find({})
  .sort({ price: -1, name: 1 })
  .skip((page - 1) * pageSize)
  .limit(pageSize)
  .toArray();
▶ Experimente

6. Noções básicas sobre índices

(1) Criar um índice

Os índices aceleram as consultas, mas aumentam a sobrecarga de gravação e o espaço de armazenamento.

▶ Exemplo: Criação de um índice

JAVASCRIPT
await products.createIndex({ name: 1 });
await products.createIndex({ category: 1, price: -1 });
await products.createIndex({ name: 'text' });

const indexes = await products.indexes();
console.log(indexes);
▶ Experimente

(2) Índices exclusivos e índices compostos

▶ Exemplo: Índice exclusivo

JAVASCRIPT
await products.createIndex({ sku: 1 }, { unique: true });
▶ Experimente

7. Processo de conexão e operação do MongoDB

100%
flowchart TD
    A[App Launch] --> B[Create MongoClient]
    B --> C[client.connect]
    C -->|Success| D[Get db Examples]
    C -->|Failure| E[Error Handling/Retry]
    E --> C
    D --> F[Get collection]
    F --> G{CRUD Operation}
    G -->|Write| H[insertOne / insertMany]
    G -->|Read| I[find / findOne]
    G -->|Update| J[updateOne / updateMany]
    G -->|Delete| K[deleteOne / deleteMany]
    H --> L[Back insertedId]
    I --> M[Back to the Document/Cursor]
    J --> N[Back modifiedCount]
    K --> O[Back deletedCount]
    L --> P{Continue?}
    M --> P
    N --> P
    O --> P
    P -->|Yes| G
    P -->|No| Q[client.close]
    Q --> R[Exit the app]


8. Exemplo abrangente: Camada de acesso a dados de gerenciamento de produtos

JAVASCRIPT
const { MongoClient, ObjectId } = require('mongodb');

class ProductRepository {
  constructor(uri, dbName) {
    this.client = new MongoClient(uri, {
      maxPoolSize: 10,
      serverSelectionTimeoutMS: 5000,
    });
    this.dbName = dbName;
    this.collection = null;
  }

  async connect() {
    await this.client.connect();
    const db = this.client.db(this.dbName);
    this.collection = db.collection('products');
    await this.collection.createIndex({ name: 1 });
    await this.collection.createIndex({ category: 1, price: -1 });
    console.log('ProductRepository connected');
  }

  async create(productData) {
    const doc = {
      ...productData,
      createdAt: new Date(),
      updatedAt: new Date(),
    };
    const result = await this.collection.insertOne(doc);
    return { ...doc, _id: result.insertedId };
  }

  async findById(id) {
    return await this.collection.findOne({
      _id: new ObjectId(id),
    });
  }

  async findByCategory(category, page = 1, pageSize = 10) {
    const skip = (page - 1) * pageSize;
    const [items, total] = await Promise.all([
      this.collection.find({ category })
        .sort({ price: -1 })
        .skip(skip)
        .limit(pageSize)
        .project({ name: 1, price: 1, category: 1 })
        .toArray(),
      this.collection.countDocuments({ category }),
    ]);
    return { items, total, page, pageSize };
  }

  async update(id, updates) {
    const result = await this.collection.updateOne(
      { _id: new ObjectId(id) },
      { $set: { ...updates, updatedAt: new Date() } },
    );
    return result.modifiedCount > 0;
  }

  async delete(id) {
    const result = await this.collection.deleteOne({
      _id: new ObjectId(id),
    });
    return result.deletedCount > 0;
  }

  async disconnect() {
    await this.client.close();
    console.log('ProductRepository disconnected');
  }
}

async function main() {
  const repo = new ProductRepository(
    'mongodb://localhost:27017',
    'ecommerce',
  );
  try {
    await repo.connect();
    const created = await repo.create({
      name: 'Wireless Mouse',
      price: 29.99,
      category: 'electronics',
      specs: { dpi: 16000, buttons: 6 },
    });
    console.log('Created:', created._id);
    const found = await repo.findById(created._id);
    console.log('Found:', found.name);
    await repo.update(created._id, { price: 24.99 });
    const page = await repo.findByCategory('electronics', 1, 10);
    console.log('Page items:', page.items.length);
    await repo.delete(created._id);
    console.log('Deleted');
  } finally {
    await repo.disconnect();
  }
}

main().catch(console.error);

❓ Perguntas Frequentes

P: Por que usar o MongoDB em vez do MySQL? R: Quando as estruturas de dados mudam com frequência e os campos não são fixos, o modelo de documentos do MongoDB pode se adaptar sem exigir modificações nas tabelas; se o negócio envolver um grande número de transações e relações complexas, o MySQL é mais adequado.

P: O que é o ObjectId? R: O ObjectId é um identificador único de 12 bytes gerado automaticamente pelo MongoDB. Os primeiros 4 bytes correspondem a um carimbo de data/hora; é possível recuperar a hora de criação usando id.getTimestamp() sem a necessidade de campos adicionais.

P: Como deve ser definido o tamanho do pool de conexões? R: Geralmente, defina-o entre 5 e 10 vezes o número de núcleos da CPU (maxPoolSize); para aplicativos com uso intensivo de E/S, ele pode ser aumentado adequadamente. Defina minPoolSize entre 2 e 5 para evitar atrasos na inicialização a frio.

P: Como devo lidar com falhas de conexão? R: Defina o parâmetro serverSelectionTimeoutMS para limitar o tempo de espera, registre o erro no bloco catch e implemente uma degradação gradual; em um ambiente de produção, recomendamos o uso de um mecanismo de repetição de tentativas e verificações de integridade.

P: Para quais cenários o MongoDB é adequado? R: Ele é adequado para cenários que exigem esquemas flexíveis e operações frequentes de leitura/gravação, como gerenciamento de conteúdo, análise de logs, dados de IoT e catálogos de produtos; não é adequado para sistemas financeiros essenciais que exigem forte consistência transacional.

P: É possível misturar 1s e 0s na projeção? R: Exceto pelo _id, não é possível misturá-los — use apenas 1s para incluir os campos especificados ou apenas 0s para excluí-los; o _id é retornado por padrão e pode ser definido como 0 individualmente para excluí-lo.



9. Exercícios

  1. Escreva um script para se conectar a uma instância local do MongoDB e inserir 5 documentos de produtos de categorias diferentes, cada um contendo pelo menos 3 campos diferentes.
  2. Implementar uma consulta por faixa de preço ($gte/$lte) e ordenar os resultados em ordem decrescente por preço, retornando apenas os campos “nome” e “preço”
  3. Use a combinação $in e $regex para pesquisar produtos cuja categoria conste na lista especificada e cujo nome contenha uma palavra-chave específica
  4. Crie índices compostos para campos consultados com frequência e use explain() para comparar as diferenças nos planos de execução antes e depois da indexação.
  5. Crie uma função genérica de consulta paginada que aceite os parâmetros filter, projection, sort, page e pageSize

📖 Resumo


📝 Exercícios

  1. Conclua todos os exemplos de código desta lição e certifique-se de que cada um deles seja executado corretamente.
  2. Modifique o exemplo completo e adicione suas próprias extensões
  3. Analise a documentação oficial, identifique 1 ou 2 APIs que não foram abordadas nesta aula e escreva um código de teste para elas.
  4. Reflexão: Como você aplicaria o que aprendeu nesta aula a um projeto do mundo real?
  5. Tente combinar o que você aprendeu nesta aula com o conteúdo das aulas anteriores para criar um pequeno projeto.
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%