Curso
Como um banco de dados NoSQL popular, o MongoDB oferece uma forma flexível e escalável de gerenciar seus dados. Este guia é o seu ponto de partida para dominar sua intuitiva Query API, que permite interagir com seus dados usando BSON (Binary JSON) de forma simples, otimizado para eficiência e tipos de dados.
Ao longo do artigo, vamos abordar as operações básicas de criar, ler, atualizar e excluir (CRUD), detalhar consultas de precisão com filtros e projeção, explorar o poder dos pipelines de agregação para transformação de dados e falar sobre indexação para melhorar a performance. No fim, você terá uma base sólida para recuperar e manipular dados com eficiência nas suas coleções do MongoDB.
Conceitos essenciais: operações CRUD
A espinha dorsal de qualquer interação com banco de dados é o CRUD: criar, ler, atualizar e excluir. Vamos ver como executar cada uma no MongoDB.
Criando dados (insert)
Para adicionar novos documentos a uma coleção, você usa os métodos insert. Documentos no MongoDB são objetos no formato parecido com JSON.
insertOne()
Esse método adiciona um único documento a uma coleção.
// A sample document to insert
const newProduct = {
name: "Wireless Mouse",
brand: "Logitech",
price: 29.99,
inStock: true
};
// Insert the new document into the 'products' collection
db.products.insertOne(newProduct);
insertMany()
Esse método adiciona vários documentos de uma vez, o que é muito mais eficiente do que inserir um por um.
// An array of documents to insert
const newProducts = [
{ name: "Mechanical Keyboard", brand: "Corsair", price: 129.99, inStock: false },
{ name: "Gaming Headset", brand: "Razer", price: 99.99, inStock: true },
{ name: "Webcam", brand: "LogiTech", price: 79.99, inStock: true }
];
// Insert the array of documents into the 'products' collection
db.products.insertMany(newProducts);
Lendo dados (find)
O método find() é sua principal ferramenta para recuperar documentos de uma coleção. Quando você chama find(), ele não retorna imediatamente todos os documentos. Em vez disso, retorna um cursor. Essa é uma forma eficiente de lidar com conjuntos de resultados potencialmente grandes sem carregar tudo na memória de uma vez.
A chamada mais simples de find() não recebe argumentos e retorna um cursor para todos os documentos da coleção.
// Find and return a cursor to all documents in the 'products' collection
db.products.find();
Veja um exemplo de como é esse objeto cursor no mongosh (o shell do MongoDB) e como você pode interagir com ele:
// Find all products and assign the returned cursor to a variable
const productCursor = db.products.find();
// The variable 'productCursor' now holds the cursor object, not the documents themselves.
// To get the documents, you need to iterate over the cursor.
// You can convert the cursor to an array to see all the documents
const allProducts = productCursor.toArray();
console.log(allProducts);
// Or, you can manually iterate through the documents
while (productCursor.hasNext()) {
const product = productCursor.next();
console.log(product);
}
O próprio cursor é um objeto com vários métodos como toArray(), hasNext() e next(), que permitem recuperar e trabalhar com os documentos do conjunto de resultados.
Atualizando dados (update)
Para modificar documentos existentes, você usa os métodos update. Eles recebem dois argumentos principais: um filtro para selecionar os documentos a atualizar e um operador de atualização para especificar as mudanças. Um operador comum é $set, que define o valor de um campo.
updateOne()
Esse método atualiza o primeiro documento que corresponde ao filtro.
// Update the 'Wireless Mouse' document to set its price to 39.99
db.products.updateOne(
{ name: "Wireless Mouse" }, // Filter to find the document
{ $set: { price: 39.99 } } // Update operator
);
updateMany()
Esse método atualiza todos os documentos que atendem ao filtro informado.
// Update all 'LogiTech' brand products to be in stock
db.products.updateMany(
{ brand: "LogiTech" }, // Filter to find the documents
{ $set: { inStock: true } } // Update operator
);
Excluindo dados (delete)
Para remover documentos, você usa os métodos delete. Eles também recebem um filtro para determinar quais documentos remover.
deleteOne()
Esse método remove o primeiro documento que corresponde ao filtro.
// Delete the 'Webcam' document
db.products.deleteOne({ name: "Webcam" });
deleteMany()
Esse método remove todos os documentos que correspondem ao filtro. Para excluir todos os documentos de uma coleção, você pode passar um filtro vazio {}.
// Delete all documents that are not in stock
db.products.deleteMany({ inStock: false });
Recuperação com precisão: filtros de consulta
Filtros de consulta estão no coração do poder do MongoDB. Eles são o primeiro argumento em find() e nos métodos de update e permitem selecionar com precisão os documentos com que você quer trabalhar.
Operadores de comparação
Esses operadores permitem comparar o valor de um campo com um valor específico.
$eq (igual a)
Encontra documentos em que um campo é igual a um valor.
// Find all products that are made by 'Razer'
db.products.find({ brand: { $eq: "Razer" } });
// This can be simplified to:
// db.products.find({ brand: "Razer" });
$gt e $gte (maior que, maior ou igual a)
Encontram documentos em que o valor de um campo é maior que ($gt) ou maior ou igual a ($gte) um valor específico.
// Find all products with a price greater than 100
db.products.find({ price: { $gt: 100 } });
$lt e $lte (menor que, menor ou igual a)
Encontram documentos em que o valor de um campo é menor que ($lt) ou menor ou igual a ($lte) um valor específico.
// Find all products with a price less than or equal to 50
db.products.find({ price: { $lte: 50 } });
$ne (diferente de)
$ne encontra documentos em que um campo é diferente de um valor especificado.
// Find all products that are NOT made by 'LogiTech'
db.products.find({ brand: { $ne: "LogiTech" } });
$in e $nin (em um array, não em um array)
Encontram documentos em que o valor de um campo está ($in) ou não está ($nin) em um array de valores.
// Find all products from 'Razer' or 'Corsair'
db.products.find({ brand: { $in: ["Razer", "Corsair"] } });
Operadores lógicos
Operadores lógicos combinam múltiplas condições para criar consultas complexas.
$and
$and combina condições de consulta com um E lógico. Todas as condições devem ser verdadeiras.
// Find all products with a price greater than 50 AND are in stock
db.products.find({ $and: [{ price: { $gt: 50 } }, { inStock: true }] });
// This can be simplified by just listing the conditions:
// db.products.find({ price: { $gt: 50 }, inStock: true });
$or
Combina condições de consulta com um OU lógico. Pelo menos uma condição deve ser verdadeira.
// Find all products with a brand of 'Corsair' OR a price less than 40
db.products.find({ $or: [{ brand: "Corsair" }, { price: { $lt: 40 } }] });
Operadores de elemento e de avaliação
Esses operadores oferecem ainda mais flexibilidade para filtrar.
$exists
$exists retorna documentos que contêm um campo específico.
// Find all documents that have an 'inStock' field
db.products.find({ inStock: { $exists: true } });
$regex
Permite usar expressões regulares para casar padrões em campos de string.
// Find all product names that start with 'Wireless'
db.products.find({ name: { $regex: /^Wireless/ } });
Modelando a saída: projeção
Ao executar um find(), você pode optar por receber apenas um subconjunto dos campos de cada documento. Isso se chama projeção e é o segundo argumento que você passa para find(). Isso ajuda a reduzir a quantidade de dados transferidos e processados.
Incluindo campos
Você pode especificar quais campos retornar definindo seu valor como 1.
// Find all products and return only the 'name' and 'price' fields
db.products.find({}, { name: 1, price: 1 });
Excluindo campos
De forma inversa, você pode especificar quais campos ocultar definindo seu valor como 0.
// Find all products and hide the 'inStock' field
db.products.find({}, { inStock: 0 });
O campo _id sempre é retornado por padrão, a menos que você o exclua explicitamente.
O campo _id
Para ocultar o campo _id, você deve defini-lo explicitamente como 0.
// Find all products, returning only 'name' and 'price', and hiding '_id'
db.products.find({}, { _id: 0, name: 1, price: 1 });
Transformação avançada de dados: pipelines de agregação
Agregação é um framework poderoso para processamento de dados no MongoDB. Um pipeline de agregação consiste em uma série de estágios que processam documentos e passam os resultados de um estágio para o seguinte.
$match
Um estágio $match filtra documentos com base em um filtro de consulta, assim como no find(). Geralmente é o primeiro estágio para reduzir a quantidade de documentos a processar.
// Find all products with a brand of 'LogiTech'
db.products.aggregate([
{ $match: { brand: "LogiTech" } }
]);
$group
O estágio $group agrupa documentos por uma expressão _id específica e pode executar operações de acumulador, como calcular a soma ou a média de um campo.
// Group products by brand and calculate the total number of products for each brand
db.products.aggregate([
{ $group: { _id: "$brand", totalProducts: { $sum: 1 } } }
]);
$project
Um estágio $project remodela cada documento no fluxo, semelhante à projeção no find(). Você pode adicionar novos campos, remover existentes e manipular dados.
// Project a new field 'nameAndPrice' for each document
db.products.aggregate([
{ $project: { name: 1, price: 1, nameAndPrice: { $concat: ["$name", " (", "$price", ")"] } } }
]);
$sort
O estágio $sort reordena os documentos com base em um campo específico. O valor 1 indica ordem crescente e -1 indica ordem decrescente.
// Sort all products by price in descending order
db.products.aggregate([
{ $sort: { price: -1 } }
]);
$limit e $skip
Esses estágios são usados para paginação. $skip descarta um número específico de documentos do início do pipeline, e $limit restringe a quantidade de documentos passados ao próximo estágio.
// Skip the first 10 products and then return the next 5
db.products.aggregate([
{ $skip: 10 },
{ $limit: 5 }
]);
Um exemplo simples de pipeline
Aqui vai um exemplo completo mostrando como esses estágios funcionam juntos.
// Find the average price of all products that are currently in stock,
// grouped by brand.
db.products.aggregate([
{ $match: { inStock: true } }, // Filter for products in stock
{ $group: { _id: "$brand", averagePrice: { $avg: "$price" } } } // Group and calculate average price
]);
Turbine a performance: indexação
Índices são estruturas de dados especiais que armazenam uma pequena porção, de fácil varredura, dos dados de uma coleção. Eles melhoram significativamente o desempenho das consultas ao permitir que o MongoDB encontre e recupere documentos rapidamente sem precisar varrer a coleção inteira.
createIndex()
Você cria um índice em um campo que consulta ou ordena com frequência.
// Create a single-field index on the 'brand' field
db.products.createIndex({ brand: 1 });
O 1 indica ordem crescente para o índice. Você pode usar -1 para ordem decrescente, o que pode beneficiar consultas que ordenam nessa direção.
Criar um índice em um campo como brand fará com que consultas que filtram por brand (por exemplo, db.products.find({ brand: "Razer" })) executem muito mais rápido, especialmente conforme sua coleção cresce.
Como escolher campos para indexar
Normalmente, você deve criar índices nos campos que usa com frequência nas consultas, como os presentes em um filtro de find() ou no estágio $match de uma agregação.
- Cardinalidade: Campos com muitos valores únicos (alta cardinalidade), como o e-mail de um usuário, são excelentes candidatos a índices.
- Seletividade da consulta: Um campo que retorna um subconjunto pequeno de documentos para uma consulta específica também é um ótimo candidato.
- Ordenação: Se você frequentemente ordena os resultados por um campo específico, criar um índice nesse campo acelera bastante a ordenação.
Impacto nas consultas
Índices têm um impacto significativo na performance. Uma consulta com índice costuma ser ordens de grandeza mais rápida do que a mesma consulta sem índice.
// Conceptual illustration of performance difference
// Without an index on 'brand':
// MongoDB performs a full collection scan, checking every document.
// This is slow, especially with millions of documents.
db.products.find({ brand: "Razer" });
// With an index on 'brand':
// MongoDB uses the index to quickly locate and return only the matching documents.
// This is very fast.
db.products.find({ brand: "Razer" });
Para otimizar ainda mais as consultas, você pode usar o método db.collection.explain() para analisar a performance e ver como os índices estão sendo utilizados.
Conclusão: sua jornada rumo à proficiência em MongoDB
Você acabou de concluir um intensivão sobre a Query API do MongoDB! Agora você sabe como executar as operações centrais de CRUD, usar filtros poderosos para recuperar dados específicos, modelar a saída com projeção e transformar os dados com pipelines de agregação. Também ficou com uma noção básica de indexação para melhorar a performance.
Este guia oferece uma base sólida — e a melhor forma de dominar esses conceitos é praticando. Experimente diferentes consultas e explore a documentação completa para conhecer operadores e recursos mais avançados. Bons códigos!
MongoDB Query API: perguntas frequentes
Qual é a principal diferença entre find() e aggregate()?
O método find() é usado para recuperar documentos de forma simples, com filtragem e projeção opcionais. Já o aggregate() é um framework poderoso para processamento multiestágio, permitindo transformar, agrupar, ordenar e remodelar documentos de maneira mais complexa. Enquanto o find() lê os documentos como estão, o aggregate() ajuda a extrair novos insights dos seus dados.
Por que o MongoDB retorna um cursor em uma operação find() em vez dos documentos diretamente?
Um cursor é uma forma eficiente de lidar com conjuntos de resultados potencialmente grandes. Ao retornar um cursor, o MongoDB evita carregar todos os documentos na memória de uma vez. Isso é crucial para performance e escalabilidade, especialmente ao lidar com milhões de documentos. O cursor permite iterar pelos resultados conforme necessário, buscando documentos em lotes.
Quando devo usar updateOne() vs. updateMany()?
Use updateOne() quando precisa modificar apenas o primeiro documento que corresponde ao filtro especificado. Isso é ideal quando você espera que apenas um documento corresponda, como ao filtrar por um identificador único. Use updateMany() quando quiser atualizar todos os documentos que atendem aos critérios do filtro.
Como os índices melhoram a performance das consultas?
Índices são estruturas de dados especiais que armazenam um subconjunto pequeno e organizado dos dados de uma coleção. Eles aceleram significativamente as consultas ao permitir que o MongoDB localize documentos rapidamente, sem precisar varrer a coleção inteira. Em vez de verificar documento por documento, o banco usa o índice para ir direto aos documentos que correspondem, tornando a operação muito mais rápida.
Posso combinar projeção com agregação?
Sim, a projeção é uma parte importante do pipeline de agregação. O estágio $project é usado para remodelar documentos, adicionar novos campos ou remover existentes. Ele costuma vir após estágios como $match ou $group para formatar a saída do pipeline, dando a você controle fino sobre a estrutura final dos dados.
Karen é uma engenheira de dados apaixonada por criar plataformas de dados escalonáveis. Ela tem experiência em automação de infraestrutura com o Terraform e está animada para compartilhar seus conhecimentos em postagens de blog e tutoriais. Karen é uma construtora de comunidades e é apaixonada por promover conexões entre profissionais de dados.

