MongoDB com NodeJS
Olá leitor, na lição anterior, você aprendeu sobre o conceito principal dos bancos de dados não relacionais (NoSQL), e também viu sobre MongoDB.
Hoje, você aprenderá a conectar suas aplicações feitas com NodeJS em conjunto com o banco MongoDB!
Preparado? 😉
Criando nosso projeto de testes
Antes de colocarmos a mão na massa, é deveras importante que você configure o seu projeto inicial.
Para isso, eu criei uma pasta chamada de MongoDB dentro da minha área de trabalho (desktop):
Com o seu terminal (Prompt de Comando) aberto na pasta raiz que acabamos de criar, precisamos inicializar o nosso projeto por meio do NPM
, sendo assim, execute o seguinte comando abaixo:
npm init -y
A flag -y
, como você já deve saber, cria um novo projeto de forma enxuta, respondendo SIM para tudo 😅
Por fim, não se esqueça de criar seu index.js
, com uma mensagem bem legal de boas vindas:
console.log('Olá Mundo!');
Instalando o MongoDB
Na lição anterior, você aprendeu a instalar o MongoDB junto com diversas outras ferramentas que estão relacionadas a ele.
Para seguir a diante, é obrigatório que você tenha o MongoDB instalado na sua máquina local, ok?
MongoDB instalado? Banco criado com o MongoDB Shell? Então você já esta pronto para conectá-lo com o NodeJS 😉
Instalando o driver do MongoDB no NodeJS
Para instalar a biblioteca (driver) do MongoDB em sua aplicação NodeJS, você vai precisar executar o seguinte comando dentro do seu terminal (Prompt de Comando), na qual deverá estar aberto na pasta raiz do seu projeto:
npm install mongodb
Feito isso, vamos conectar nossa aplicação como MongoDB 😉
Criando nosso arquivo de conexão
Dentro da pasta raiz do seu projeto, vamos criar uma nova pasta chamada de db, contendo um arquivo chamado de connectionMongoDB.js
:
Dentro do arquivo (connectionMongoDB.js
) insira o seguinte código:
const { MongoClient } = require('mongodb');
const uri = 'mongodb://localhost:27017';
const client = new MongoClient(uri);
async function run() {
try {
await client.connect();
console.log('Conectado ao MongoDB!');
} catch (e) {
console.log('Erro ao conectar ao MongoDB!', e);
}
finally {
await client.close();
console.log('Conexão fechada com o MongoDB!');
}
}
run();
module.exports = client;
Vamos às explicações 😉
const { MongoClient } = require('mongodb');
No comando acima, você está importando a classe MongoClient
da biblioteca mongodb
, que é totalmente necessária para criar a conexão com o banco de dados. Sem essa biblioteca, não conseguiremos interagir com o MongoDB.
const uri = 'mongodb://localhost:27017';
A variável uri
define o endereço de onde o servidor MongoDB está rodando. No nosso caso, ele está rodando localmente na porta padrão 27017
.
const client = new MongoClient(uri);
Em seguida, instânciamos um novo cliente do MongoClient
, passando a uri
como parâmetro.
async function run() {
try {
await client.connect();
console.log('Conectado ao MongoDB!');
} catch (e) {
console.log('Erro ao conectar ao MongoDB!', e);
} finally {
await client.close();
console.log('Conexão fechada com o MongoDB!');
}
}
Após isso, nós criamos uma função assíncrona que vai lidar com a nossa tentativa de conexão (client.connect) com o MongoDB.
run();
Por fim, executamos a função assíncrona que acabamos de criar (run()), para que a nossa aplicação tente se comunicar com o MongoDB.
Agora, basta chamar este arquivo dentro do seu programa principal (index.js) e executar um node ./index.js
:
const mongoClient = require('./db/connectionMongoDB');
console.log('Olá Mundo!');
Se tudo ocorrer bem, você vai se deparar com a seguinte mensagem no console
:
Indicando que a comunicação com o seu banco de dados foi um sucesso 🤩
Arquivo de conexão para autenticação
Caso você tiver implementado um sistema de autenticação dentro do MongoDB, basta modificar a sua uri
informando o login e senha escolhidos, por exemplo:
// Modifique a URI com usuário e senha
const uri = 'mongodb://usuario:senha@localhost:27017';
Só não se esquela de modificar o usuario
e a senha
da sintaxe acima para suas credênciais originais.
Inserindo dados no MongoDB
Como visto na lição anterior, você não pode simplesmente criar um banco de dados e uma collection
sem uma document
.
A mesma regra vale para quando você está usando o MongoDB em conjunto com o NodeJS.
Sendo assim, inevitavelmente você vai precisar inserir um novo registro (document) na sua collection
, para que posteriormente, o MongoDB faça a criação do banco de dados.
O que eu quero dizer com isso? É que não existe um comando específico para criar somente o database
, e outro para criar somente uma collection
.
Como veremos a seguir, a partir do momento que selecionamos um database
e uma collection
, o driver do MongoDB trabalha com a possibilidades deles existirem ou não.
Se não existirem, eles serão criados a partir do momento que inserirmos um novo registro (document), mas se eles existirem... bem, o MongoDB só estará selecionando tais entidades 😅
No comando abaixo, eu trouxe um exemplo bem simples, onde estamos usando o método insertOne
para inserir um novo document
em uma collection
chamada minhaCollection
, dentro de uma base de dados chamada de meuBanco
.
const mongoClient = require('./db/connectionMongoDB');
async function createDatabaseAndCollection() {
try {
// Conectando ao MongoDB
await mongoClient.connect();
// Criando ou acessando o banco de dados (nome do banco de dados: 'meuBanco')
const db = mongoClient.db('meuBanco');
// Criando ou acessando a collection (nome da collection: 'minhaCollection')
const collection = db.collection('minhaCollection');
// Inserindo um documento
const result = await collection.insertOne({
nome: 'João',
idade: 30,
cidade: 'São Paulo'
});
console.log('Documento inserido com sucesso!', result);
} catch (error) {
console.log('Erro ao criar banco de dados ou inserir documento:', error);
} finally {
// Fechar a conexão com o MongoDB
await mongoClient.close();
console.log('Conexão fechada com o MongoDB!');
}
}
createDatabaseAndCollection();
O resultado final será este no console
:
Caso ocorra o erro: Conexão fechada com o MongoDB! Erro ao criar banco de dados ou inserir documento: MongoTopologyClosedError: Topology is closed.
Isso acontece porque nós estamos fechando a conexão com o MongoDB antes da operação ser concluída. Sendo assim, abra o arquivo connectionMongoDB.js
, e comente toda a linha do finally
:
const { MongoClient } = require('mongodb');
const uri = 'mongodb://localhost:27017';
const client = new MongoClient(uri);
async function run() {
try {
await client.connect();
console.log('Conectado ao MongoDB!');
} catch (e) {
console.log('Erro ao conectar ao MongoDB!', e);
}
finally {
//await client.close();
//console.log('Conexão fechada com o MongoDB!');
}
}
run();
module.exports = client;
Fique tranquilo enquanto a isso, pois no próprio index.js
, mais especificamente dentro da função createDatabaseAndCollection
, nós já estamos fechando a conexão com o banco, logo após o comando se inserção.
E falando nessa função, vamos às explicações 😉
const db = mongoClient.db('meuBanco');
O comando acima cria ou acessa um banco de dados chamado meuBanco
. No caso do MongoDB, ele cria automaticamente um banco de dados quando você tenta usá-lo (caso ele ainda não exista).
Observação: esse é um dos maiores problemas quando você trabalha com databases
e collections
do MongoDB, pois se você errar a nomenclatura deles, ele vai passar a criar seus documents em novas tabelas e bancos 😂 (sendo assim, salve o nome do seu banco e de suas collections em um lugar global)
const collection = db.collection('minhaCollection');
O comando acima, cria ou acessa uma collection
chamada minhaCollection
no banco de dados meuBanco
. Funciona da mesma forma que o comando visto anteriormente, ou seja, se não houver essa collection
, ele cria uma de forma automática.
const result = await collection.insertOne({
nome: 'João',
idade: 30,
cidade: 'São Paulo'
});
Por fim, nós estamos chamando o comando insertOne
, que você já aprendeu sobre ele aqui, em conjunto com um JSON
embutido.
Sabe aqueles comandos de insertOne
, find
, updateMany
e muitos outros que aprendemos na lição passada? Então, todos eles funcionam em conjunto com o NodeJS.
Mas não se esqueça de sempre instânciar sua base, selecionar uma collection
, para posteriormente usar os métodos de CRUD aceitos pelo MongoDB 😁
E no final, nunca se esqueça de fechar a conexão com o banco de dados!
Selecionando dados no MongoDB
Como dito anteriormente, você pode utilizar todos os métodos de seleção, junto com os operadores que vimos na lição anterior.
Sendo assim, vou te explicar de forma bem rápida como você pode selecionar alguns dados da sua tabela.
Para selecionar todos os registros, podemos usar o método find()
:
const mongoClient = require('./db/connectionMongoDB');
async function findAllDocuments() {
const db = mongoClient.db('meuBanco');
const collection = db.collection('minhaCollection');
// Buscando todos os documentos
const documents = await collection.find({}).toArray();
console.log('Todos os documentos:', documents);
//Fecha a conexão:
await mongoClient.close();
}
findAllDocuments();
Para selecionar registros que obedecem a um determinado filtro, use citações em JSON
dentro do find()
:
const mongoClient = require('./db/connectionMongoDB');
async function findWithFilter() {
const db = mongoClient.db('meuBanco');
const collection = db.collection('minhaCollection');
// Buscando documentos onde cidade = 'São Paulo'
const documents = await collection.find({ cidade: 'São Paulo' }).toArray();
console.log('Documentos filtrados por cidade:', documents);
//Fecha a conexão:
await mongoClient.close();
}
findWithFilter();
Você pode definir quais campos deseja incluir ou excluir no resultado:
const mongoClient = require('./db/connectionMongoDB');
async function findWithProjection() {
const db = mongoClient.db('meuBanco');
const collection = db.collection('minhaCollection');
// Projeção para retornar apenas os campos 'nome' e 'cidade'
const documents = await collection.find({}, { projection: { nome: 1, cidade: 1, _id: 0 } }).toArray();
console.log('Documentos com projeção:', documents);
//Fecha a conexão:
await mongoClient.close();
}
findWithProjection()
Veja esse último exemplo onde estamos usando alguns dos métodos que aprendemos anteriormente:
const mongoClient = require('./db/connectionMongoDB');
async function findWithSortAndLimit() {
const db = mongoClient.db('meuBanco');
const collection = db.collection('minhaCollection');
// Ordenando por idade (descendente) e limitando a 5 documentos
const documents = await collection.find({})
.sort({ idade: -1 }) // Ordena por idade (decrescente)
.limit(5) // Limita a 5 documentos
.toArray();
console.log('Documentos ordenados por idade e limitados:', documents);
//Fecha a conexão:
await mongoClient.close();
}
findWithSortAndLimit()
Atualizando dados no MongoDB
Como dito anteriormente, você pode utilizar todos os métodos de atualização, junto com seus operadores que vimos na lição anterior.
Dito isso, vamos começar realizando uma atualização pelo nome:
const mongoClient = require('./db/connectionMongoDB');
async function updateByName() {
const db = mongoClient.db('meuBanco');
const collection = db.collection('minhaCollection');
// Atualizando o documento onde nome = 'João'
const updateResult = await collection.updateOne(
{ nome: 'João' }, // Filtro
{ $set: { cidade: 'Rio de Janeiro' } } // Atualização
);
console.log('Documento atualizado com base no nome:', updateResult);
// Fechando a conexão
await mongoClient.close();
}
updateByName();
Vamos atualizar agora, um document
, usando o ObjectId
dessa vez:
const mongoClient = require('./db/connectionMongoDB');
const { ObjectId } = require('mongodb');
async function updateById() {
const db = mongoClient.db('meuBanco');
const collection = db.collection('minhaCollection');
// O _id do documento a ser atualizado
const documentId = '65145e8c5f4cfc43568b7e36'; // Substitua pelo ObjectId real
// Atualizando o documento onde _id é igual ao especificado
const updateResult = await collection.updateOne(
{ _id: new ObjectId(documentId) }, // Filtro com ObjectId
{ $set: { idade: 35 } } // Atualização
);
console.log('Documento atualizado com base no _id:', updateResult);
// Fechando a conexão
await mongoClient.close();
}
updateById();
Removendo dados no MongoDB
Como dito anteriormente, você pode utilizar todos os métodos de remoção, junto com seus operadores que vimos na lição anterior.
Para remover um documento por nome
, use a lógica abaixo:
const mongoClient = require('./db/connectionMongoDB');
async function removeByName() {
const db = mongoClient.db('meuBanco');
const collection = db.collection('minhaCollection');
// Removendo o documento onde nome = 'João'
const deleteResult = await collection.deleteOne({ nome: 'João' });
console.log('Documento removido com base no nome:', deleteResult);
// Fechando a conexão
await mongoClient.close();
}
removeByName();
Caso você queira fazer a remoção pelo ObjectId
basta seguir a lógica abaixo:
const mongoClient = require('./db/connectionMongoDB');
const { ObjectId } = require('mongodb');
async function removeById() {
const db = mongoClient.db('meuBanco');
const collection = db.collection('minhaCollection');
// O _id do documento a ser removido
const documentId = '65145e8c5f4cfc43568b7e36'; // Substitua pelo ObjectId real
// Removendo o documento onde _id é igual ao especificado
const deleteResult = await collection.deleteOne({ _id: new ObjectId(documentId) });
console.log('Documento removido com base no _id:', deleteResult);
// Fechando a conexão
await mongoClient.close();
}
removeById();
Como fica o conceito de JOINs no MongoDB?
No MongoDB, o conceito de joins como em bancos de dados relacionais (como MySQL ou PostgreSQL) não existe de maneira nativa.
Como você já deve saber, o MongoDB é um banco de dados NoSQL
e usa uma abordagem de documentos em vez de tabelas e relações.
Em vez de "joins", o MongoDB usa duas abordagens principais:
- Documentos Aninhados (Embedded Documents)
- Lookup (Equivalente ao Join)
Veremos o funcionamento delas a seguir 😉
Documentos Aninhados (Embedded Documents)
Ao invés de fazer joins entre coleções, você pode aninhar documentos, e isso significa que os dados relacionados são armazenados juntos, dentro de um único documento:
{
"_id": 1,
"nome": "João",
"idade": 30,
"enderecos": [
{
"rua": "Rua 1",
"cidade": "São Paulo"
},
{
"rua": "Rua 2",
"cidade": "Rio de Janeiro"
}
]
}
Lookup
Mas se você realmente precisa "unir" dados de duas coleções diferentes, o MongoDB oferece o operador $lookup
no aggregation framework, que funciona como um JOIN
simples.
Supondo que você tenha duas coleções com alguns documents
:
collection
clientes:
{ "_id": 1, "nome": "João" }
{ "_id": 2, "nome": "Maria" }
collection
pedidos:
{ "_id": 101, "clienteId": 1, "produto": "Livro" }
{ "_id": 102, "clienteId": 1, "produto": "Caneta" }
{ "_id": 103, "clienteId": 2, "produto": "Caderno" }
Observe como um "JOIN"
pode ser feito:
const mongoClient = require('./db/connectionMongoDB');
async function joinCollections() {
const db = mongoClient.db('meuBanco');
const clientes = db.collection('clientes');
const pedidos = db.collection('pedidos');
// Usando $lookup para "juntar" os dados das coleções clientes e pedidos
const result = await clientes.aggregate([
{
$lookup: {
from: 'pedidos', // Coleção com a qual faremos o join
localField: '_id', // Campo local (coleção clientes)
foreignField: 'clienteId', // Campo estrangeiro (coleção pedidos)
as: 'pedidos' // Nome do campo de saída para os resultados unidos
}
}
]).toArray();
console.log(JSON.stringify(result, null, 2));
// Fechando a conexão
await mongoClient.close();
}
joinCollections();
$lookup
: funciona como um "join" entre duas coleções (clientes e pedidos).
from
: especifica a coleção com a qual fazer o join (neste caso, pedidos).
localField
: o campo da coleção principal (clientes) usado para combinar.
foreignField
: o campo da coleção secundária (pedidos) que deve corresponder ao campo localField
.
as
: nome do campo onde os resultados unidos serão colocados.
Arquivos da lição
Os arquivos que você viu durante o decorrer desta lição, podem ser encontrados neste link.
Conclusão
Nesta lição, você aprendeu a conectar o NodeJS com seu banco de dados MongoDB.
Além disso, aprendeu a executar a maioria das operações CRUD (Create, Read, Update e Delete
).
É isso, até a próxima lição 😎