Como migrar seu aplicativo Node.js do SQL para o MongoDB
Avalie esse Tutorial
Com a rápida aprovação da metodologia Agile no desenvolvimento de software, os desenvolvedores agora procuram migrar de bancos de dados SQL para NoSQL para obter mais flexibilidade e dimensionamento horizontal, o que é mais barato e eficiente para o desenvolvimento de software.
A migração de um banco de dados SQL para um banco de dados NoSQL pode ser um desafio devido a fatores importantes, como diferenças no modelo de dados, linguagem de consulta, padrões de acesso e otimização de consultas.
Neste artigo, exploraremos os principais conceitos do MongoDB, como collections, documentos e BSON, e as diferenças na modelagem de dados entre bancos de dados SQL e NoSQL. Também migraremos de um banco de dados relacional (Postgres) para o MongoDB.
Abaixo estão alguns pré-requisitos que você precisará antes de prosseguir com este artigo:
- Conhecimento de JavaScript
- Experiência na construção de aplicativos Node.js
- Experiência com banco de dados SQL e Postgre
- Node.js ≥v20 instalado
Nesta seção, migraremos o banco de dados e as queries de um aplicativo de backend do Node.js do Postgres para o MongoDB. O aplicativo será um aplicativo de lista telefônica pública com os seguintes recursos:
- Registro e login do usuário: as senhas são criptografadas usando o bcrypt e o JWT é usado para autenticação.
- Operações CRUD:
- Criar contato: Usuários autenticados podem criar contatos.
- Obtenha contatos: obtenha contatos com a contagem da taxa de chamadas e detalhes do usuário, filtrados por intervalo de datas e ordenados pela contagem da taxa de chamadas.
- Obter contato por ID: recupere um único contato por ID para o usuário autenticado.
- Atualizar contato: usuários autenticados podem atualizar seus contatos.
- Excluir contato: usuários autenticados podem excluir seus contatos.
Abra
psql
e execute o seguinte comando para criar as tabelas necessárias para o aplicativo:1 CREATE TABLE users ( 2 id SERIAL PRIMARY KEY, 3 username VARCHAR(100) UNIQUE NOT NULL, 4 password VARCHAR(100) NOT NULL, 5 email VARCHAR(100) UNIQUE NOT NULL, 6 created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP 7 ); 8 CREATE TABLE contacts ( 9 id SERIAL PRIMARY KEY, 10 name VARCHAR(100) NOT NULL, 11 phone VARCHAR(20) NOT NULL, 12 email VARCHAR(100), 13 user_id INTEGER REFERENCES users(id) ON DELETE CASCADE, 14 created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP 15 ); 16 CREATE TABLE rates ( 17 id SERIAL PRIMARY KEY, 18 description TEXT NOT NULL, 19 contact_id INTEGER REFERENCES contacts(id) ON DELETE CASCADE, 20 user_id INTEGER REFERENCES users(id) ON DELETE CASCADE, 21 created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP 22 );
Crie um projeto Node.js e instale as seguintes dependências:
1 "dependencies": { 2 "bcryptjs": "^2.4.3", 3 "express": "^4.19.2", 4 "jsonwebtoken": "^9.0.2", 5 "pg": "^8.11.5" 6 }
Você pode instalar todos os pacotes necessários com o seguinte comando:
1 npm install bcryptjs express jsonwebtoken pg
Crie um arquivo
.env.postgres
e adicione as variáveis de ambiente a seguir. Você precisará alterar os valores para usar as credenciais para se conectar ao seu banco de dados.1 DB_USER=your_username 2 DB_HOST=localhost 3 DATABASE=your_DB_name 4 DB_PASSWORD=your_password 5 DB_PORT=5432 6 SECRET_KEY=your_jwt_secret_key
Crie um arquivo
postgres.js
no diretório raiz do projeto e adicione o seguinte:1 import express from 'express'; 2 import bcrypt from 'bcryptjs'; 3 import jwt from 'jsonwebtoken'; 4 import pg from 'pg'; 5 6 const { Pool } = pg; 7 8 const app = express(); 9 const port = 3000; 10 11 app.use(express.json()); 12 13 const pool = new Pool({ 14 user: process.env.DB_USER, 15 host: process.env.DB_HOST, 16 database: process.env.DATABASE, 17 password: process.env.DB_PASSWORD, 18 port: process.env.DB_PORT, 19 }); 20 21 // JWT secret key 22 const SECRET_KEY = process.env.SECRET_KEY; 23 24 /* START FEATURE IMPLEMENTATION*/ 25 26 /* END FEATURE IMPLEMENTATION*/ 27 28 // Start server 29 app.listen(port, () => { 30 console.log(`Server running on port ${port}`); 31 });
Certifique-se de que seu package.json inclua
"type": "module"
.Definimos com sucesso um aplicativo de backend Nodejs e configuramos o banco de dados Postgres usando a estrutura Express.
Você pode iniciar seu servidor executando:
1 node --env-file=.env.postgres postgres.js
O uso do parâmetro
--env-file
injetará as variáveis de ambiente e você poderá usá-las por meio process.env
.Vamos prosseguir com a implementação dos recursos do aplicativo.
Registro do usuário:
1 app.post('/register', async (req, res) => { 2 const { username, email, password } = req.body; 3 const salt = await bcrypt.genSalt(10); 4 const hashedPassword = await bcrypt.hash(password, salt); 5 const result = await pool.query( 6 'INSERT INTO users (username, email, password) VALUES ($1, $2, $3) RETURNING *', 7 [username, email, hashedPassword] 8 ); 9 const { ...user } = result.rows[0]; 10 11 res.status(201).json({...user, password: null}); 12 });
O endpoint de registro de usuário garante o manuseio seguro de senhas usando
bcrypt
para o hash da senha e executa uma query SQL para inserir o novo usuário na tabelausers
no banco de dados PostgreSQL por meio do pool de conexões.Login do usuário:
1 app.post('/login', async (req, res) => { 2 const { email, password } = req.body; 3 4 const user = await pool.query('SELECT * FROM users WHERE email = $1', [email]); 5 6 let validPass = false; 7 8 if (user.rows[0]) validPass = await bcrypt.compare(password, user.rows[0].password); 9 10 if (!validPass) return res.status(400).json({ message: 'Invalid credentials' }); 11 12 const token = jwt.sign({ id: user.rows[0].id, email: user.rows[0].email }, SECRET_KEY, { expiresIn: '1h' }); 13 14 res.status(200).json({ token }); 15 16 });
O endpoint de login do usuário garante o tratamento seguro da autenticação do usuário usando o bcrypt para validação de senha e o JWT para gerenciamento de sessões.
Middleware para autenticar usuários:
1 const authenticateToken = (req, res, next) => { 2 const token = req.header('Authorization'); 3 if (!token) return res.status(401).json({ message: 'Access Denied' }); 4 const verified = jwt.verify(token.split(" ")[1], SECRET_KEY); 5 req.user = verified; 6 next(); 7 };
Essa função de middleware garante que somente solicitações com tokens JWT válidos possam acessar rotas protegidas, aumentando a segurança do aplicativo.
Criar contato:
1 app.post('/contacts', authenticateToken, async (req, res) => { 2 const { name, phone, email } = req.body; 3 const result = await pool.query( 4 'INSERT INTO contacts (name, phone, email, user_id) VALUES ($1, $2, $3, $4) RETURNING *', 5 [name, phone, email, req.user.id] 6 ); 7 res.status(201).json(result.rows[0]); 8 });
O endpoint create contact cria novos contatos e garante que somente usuários autenticados possam executar essa ação.
Obter contato por ID:
1 app.get('/contacts/:id', authenticateToken, async (req, res) => { 2 const { id } = req.params; 3 const result = await pool.query('SELECT * FROM contacts WHERE id = $1 AND user_id = $2', [id, req.user.id]); 4 if (result.rows.length === 0) return res.status(404).json({ message: 'Contact not found' }); 5 res.status(200).json(result.rows[0]); 6 });
O ponto de extremidade get contact by ID permite que apenas usuários autenticados busquem um contato específico pelo seu ID e verifica se ele pertence ao usuário autenticado.
Contato de atualização:
1 app.put('/contacts/:id', authenticateToken, async (req, res) => { 2 const { id } = req.params; 3 const { name, phone, email } = req.body; 4 const result = await pool.query( 5 'UPDATE contacts SET name = $1, phone = $2, email = $3 WHERE id = $4 AND user_id = $5 RETURNING *', 6 [name, phone, email, id, req.user.id]\ 7 ); 8 if (result.rows.length === 0) return res.status(404).json({ message: 'Contact not found or not authorized' }); 9 res.status(200).json(result.rows[0]); 10 });
O ponto de extremidade de atualização de contato permite que apenas usuários autenticados acessem e atualizem seus contatos.
Excluir contato:
1 app.delete('/contacts/:id', authenticateToken, async (req, res) => { 2 const { id } = req.params; 3 const result = await pool.query('DELETE FROM contacts WHERE id = $1 AND user_id = $2 RETURNING *', [id, req.user.id]); 4 if (result.rows.length === 0) return res.status(404).json({ message: 'Contact not found or not authorized' }); 5 res.status(200).json(result.rows[0]); 6 });
O ponto de extremidade de exclusão de contato permite que apenas usuários autenticados excluam seus contatos.
Adicionar taxa de chamada:
1 app.post('/contacts/:id/rates', authenticateToken, async (req, res) => { 2 const { id } = req.params; 3 const { description } = req.body; 4 const result = await pool.query( 5 'INSERT INTO rates (body, contact_id, user_id) VALUES ($1, $2, $3) RETURNING *', 6 [description, id, req.user.id] 7 ); 8 res.status(201).json(result.rows[0]); 9 });
O endpoint de adição de taxa de chamada permite que apenas usuários autenticados avaliem um contato específico por sua ID.
As taxas estão associadas a contatos em um relacionamento de um para muitos. A coluna
contact_id
na tabela de taxas é uma chave estrangeira que faz referência à coluna id na tabela de contatos.Essa chave estrangeira estabelece um relacionamento em que cada taxa está vinculada a um contato específico.
Ter uma relação definida permite consultas eficientes que podem unir duas ou mais tabelas.
Por exemplo, você pode buscar rapidamente um contato junto com todas as suas taxas associadas ou dados agregados, como o número de taxas por contato.
Obter contatos:
1 app.get('/contacts', async (req, res) => { 2 let { startDate, endDate } = req.query; 3 if (!endDate) { 4 endDate = new Date().toISOString(); 5 } else { 6 endDate = new Date(endDate).toISOString(); 7 } 8 9 if (!startDate) {\ 10 const now = new Date(); 11 const pastDate = new Date(now); 12 pastDate.setDate(now.getDate() - 7); 13 startDate = pastDate.toISOString(); 14 } else { 15 startDate = new Date(startDate).toISOString(); 16 } 17 18 const result = await pool.query(` 19 SELECT 20 contacts.id, contacts.name, contacts.phone, contacts.created_at, 21 users.username, 22 COUNT(rates.id) AS call_rate 23 FROM contacts 24 LEFT JOIN users ON contacts.user_id = users.id 25 LEFT JOIN rates ON contacts.id = rates.contact_id 26 WHERE contacts.created_at BETWEEN $1 AND $2 27 GROUP BY contacts.id, users.username 28 ORDER BY call_rate DESC 29 `, [startDate, endDate]); 30 res.status(200).json(result.rows); 31 });
O endpoint get contacts recupera e agrega dados de contato, garantindo que somente contatos dentro do intervalo de datas especificado sejam incluídos nos resultados. Ele também fornece informações úteis sobre o número de chamadas associadas a cada contato, ordenadas pelo número de classificações de chamadas.
Cláusula SELECT: a cláusula SELECT seleciona a coluna especificada na tabela para selecionar os dados.
Cláusula FROM: A cláusula FROM especifica a tabela da qual selecionar dados.
LEFT JOIN usuários ON contatos.user_id = users.id: Isso une a tabela de contatos à tabela de usuários com a condição de que o user_id na tabela de contatos corresponda ao id na tabela de usuários.
Taxas de junção à esquerda em contatos.id = taxas.contact_id: Isso une a tabela de contatos à tabela de taxas, com a condição de que o ID na tabela de contatos corresponda ao Contact_id na tabela de taxas.
WHERE contacts.created_at ENTRE $1 E $2: Isso filtra os contatos para incluir apenas aqueles criados entre as datas especificadas por $1 (StartDate) e $2 (EndDate).
GROUP BY contacts.id, users.username: Isto agrupa os resultados por Contacts.id e users.username. Isso é necessário porque estamos usando uma função agregada (COUNT(rates.id)), e SQL requer que todas as colunas não agregadas na cláusula SELECT sejam incluídas na cláusula GROUP BY.
ORDENAR BY call_rate DESC: Ordena os resultados por call_rate em ordem decrescente (DESC). Isso significa que os contatos com o maior número de taxas (ou chamadas) aparecerão primeiro nos resultados.
Para testar sua implementação, não se esqueça de parar e reiniciar seu servidor.
Como podemos ver, o PostgreSQL segue um modelo de dados relacional. Ao mesmo tempo, o MongoDB é um banco de dados orientado a documentos NoSQL, portanto, precisamos redesenhar nosso esquema para se adequar ao modelo baseado em documentos do MongoDB. Na seção de migração do SQL, identificaremos as entidades e relacionamentos em nosso esquema PostgreSQL e mapeamos para as collections e documentos do MongoDB.
Para configurar o MongoDB para uso com nosso aplicativo Node.js, usaremos o MongoDB Atlas, um serviço de banco de dados em várias nuvens que simplifica a implantação e o gerenciamento de seus bancos de dados com apenas alguns cliques.
Ele também oferece uma camada gratuita para sempre, sem requisitos de cartão de crédito. Quão legal é isso?
Para criar um cluster de banco de dados, siga os Docs.
Escolha a opção de cluster compartilhado para uma camada gratuita para sempre. A configuração padrão é suficiente para nosso aplicativo de demonstração.
Ao criar seu cluster de banco de dados, você será solicitado a adicionar um usuário e uma senha de banco de dados para seu cluster de banco de dados. Certifique-se de salvar o nome de usuário e a senha onde você pode referenciar, pois você precisará deles para se conectar ao cluster de banco de dados.
Crie um projeto Node.js e instale as seguintes dependências:
1 "dependencies": { 2 "express": "^4.19.2", 3 "mongodb": "^8.4.0", 4 "bcryptjs": "^2.4.3", 5 "jsonwebtoken": "^9.0.2", 6 }
Você pode instalar as bibliotecas com:
1 npm install mongodb express bcryptjs jsonwebtoken
Crie um
.env.mongodb
arquivo e adicione as seguintes variáveis de ambiente:1 SECRET_KEY=your_jwt_secret_key 2 DB_USER=your_cluster_username 3 DB_PASSWORD=your_cluster_password 4 DATABASE=users 5 CLUSTER_URI=your_cluster_uri
Crie um arquivo
mongodb.js
no diretório raiz do projeto e adicione o seguinte:1 import { MongoClient, ObjectId } from 'mongodb'; 2 import express from 'express'; 3 import bcrypt from 'bcryptjs'; 4 import jwt from 'jsonwebtoken'; 5 6 const app = express(); 7 app.use(express.json()); 8 9 const url = `mongodb+srv://${process.env.DB_USER}:${process.env.DB_PASSWORD}@${process.env.CLUSTER_URI}`; 10 const client = new MongoClient(url); 11 const dbName = process.env.DATABASE; 12 const SECRET_KEY = process.env.SECRET_KEY; 13 14 await client.connect(); 15 const db = client.db(dbName); 16 const usersCollection = db.collection('users'); 17 const contactsCollection = db.collection('contacts'); 18 19 /* START FEATURE IMPLEMENTATION*/ 20 21 /* END FEATURE IMPLEMENTATION*/ 22 app.listen(3000, () => { 23 console.log('Server is running on port 3000'); 24 });
Para usar o await de nível superior, você precisará habilitar o suporte ao módulo ES e garantir que seu package.json tenha
"type": "module"
.O código acima permite que seu aplicativo Node se conecte ao cluster de banco de dados.
Execute o seguinte comando para iniciar seu servidor Node:
1 node --env-file=.env.mongodb mongodb.js
Existem duas etapas aqui:
- Traduza as queries SQL para a API de query do MongoDB.
- Use o Conversor de query do MongoDB para migrar suas queries SQL para a MongoDB Query API.
O driver MongoDB Node.js é um pacote que permite que você se conecte ao MongoDB, execute operações de banco de dados e gerencie collections e documentos. Ele fornece uma solução direta e sem esquema para modelar os dados do aplicativo de forma flexível.
A primeira coisa a considerar para a migração do banco de dados são os modelos de dados. Lembre-se de como criamos tabelas e relacionamentos para o banco de dados Postgres executando o seguinte SQL no terminal
psql
:1 CREATE TABLE users ( 2 id SERIAL PRIMARY KEY, 3 username VARCHAR(100) UNIQUE NOT NULL, 4 password VARCHAR(100) NOT NULL, 5 email VARCHAR(100) UNIQUE NOT NULL, 6 created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP 7 );
Aqui está a parte boa: usando o driver MongoDB Node.js, você não precisa definir esquemas. Quando você insere um documento em uma collection, ele é criado com os campos fornecidos com ométodo de inserção.
Registrar:
1 app.post('/register', async (req, res) => { 2 const { username, email, password } = req.body; 3 4 const salt = await bcrypt.genSalt(10); 5 const hashedPassword = await bcrypt.hash(password, salt); 6 const user = { username, email, password: hashedPassword }; 7 const result = await usersCollection.insertOne(user); 8 res.status(201).json({...user, password: null}); 9 });
Esse endpoint é o equivalente do MongoDB do endpoint
register
anterior projetado para PostgreSQL. Ele usa os métodosinsertOnedo driver do MongoDB para interagir com o banco de dados. Enquanto a implementação do PostgreSQL usa uma instrução SQL INSERT
para inserir novos dados, a implementação do MongoDB usa o métodoinsertOne
para inserir novos dados em uma coleção.Login:
1 app.post('/login', async (req, res) => { 2 const { email, password } = req.body; 3 const user = await usersCollection.findOne({ email }); 4 5 let validPass = false; 6 7 if (user) validPass = await bcrypt.compare(password, user.password); 8 9 if (!validPass) return res.status(400).json({ message: 'Invalid credentials' }); 10 11 const token = jwt.sign({ sub: user._id, email: user.email }, SECRET_KEY, { expiresIn: '1h' }); 12 res.status(200).json({ token }); 13 });
Esse endpoint é o equivalente do MongoDB do endpoint
/login
anterior projetado para PostgreSQL. Ele usa os métodosfindOnedo driver do MongoDB para interagir com o banco de dados. Enquanto a implementação do PostgreSQL usa pool.query
para executar uma instrução SQL SELECT
para localizar uma linha de usuário na tabela, a implementação do MongoDB usa usersCollection.findOne
para localizar um documento do usuário na coleção.No MongoDB, o método findOne utiliza um objeto JSON para especificar a condição de consulta, que é análoga à cláusula ONDE em SQL. No SQL, users é o nome da tabela que está sendo consultada, semelhante a uma coleção no MongoDB.
Middleware para autenticar usuários:
1 const authenticateToken = (req, res, next) => { 2 const token = req.header('Authorization'); 3 if (!token) return res.status(401).json({ message: 'Access Denied' }); 4 const verified = jwt.verify(token.split(" ")[1], SECRET_KEY); 5 req.user = verified; 6 next(); 7 };
Aqui, estamos usando a mesma função que usamos no exemplo anterior.
Criar contato:
1 app.post('/contacts', authenticateToken, async (req, res) => { 2 const { name, phone, email } = req.body; 3 const contact = { name, phone, email, user_id: req.user.sub, createdAt: new Date().toISOString() }; 4 const result = await contactsCollection.insertOne(contact); 5 res.status(201).json(contact); 6 });
Esse endpoint é a versão MongoDB do endpoint POST
/contact
anterior que criamos para o PostgreSQL. Em vez de usar comandos SQL como pool.query
para adicionar uma linha de contato a uma tabela, ele usa o método ContactCollection.insertOne do MongoDB para adicionar um documento de contato a uma coleção.A conversão
req.user.id
para ObjectId garante que o ID do usuário esteja formatado corretamente e possa ser consultado e indexado com eficiência no MongoDB. Isso é importante, pois precisaremos realizar operações que envolvam a correspondência ou referência a esse ID no banco de dados.Obter contato por ID:
1 app.get('/contacts/:id', authenticateToken, async (req, res) => { 2 const { id } = req.params; 3 const contact = await contactsCollection.findOne({ _id: new ObjectId(id), user_id: req.user.sub }); 4 if (!contact) return res.status(404).json({ message: 'Contact not found' }); 5 res.status(200).json(contact); 6 });
Esse endpoint é o equivalente do MongoDB do endpoint GET
/contacts/:id
anterior projetado para PostgreSQL. Enquanto a implementação PostgreSQL usa pool.query
para executar uma declaração SQL SELECT
e a cláusulaWHERE
para localizar uma linha de contato na tabela, a implementação do MongoDB usa o contactsCollection.findOne
para localizar um documento de contato na coleção e retorna o documento encontrado.O PostgreSQL usa diretamente os parâmetros
id
e user_id
na query SQL, enquanto o MongoDB converte id
e user_id
em ObjectId
para corresponder ao formato de ID do documento do MongoDB.Contato de atualização:
1 app.put('/contacts/:id', authenticateToken, async (req, res) => { 2 const { id } = req.params; 3 const { name, phone, email } = req.body; 4 const contact = await contactsCollection.findOneAndUpdate( 5 { _id: new ObjectId(id), user_id: req.user.sub }, 6 { $set: req.body }, 7 { returnOriginal: false } 8 ); 9 if (!contact) return res.status(404).json({ message: 'Contact not found or not authorized' }); 10 res.status(200).json(contact); 11 });
Esse endpoint é o equivalente do MongoDB do endpoint PUT
/contacts
anterior projetado para PostgreSQL. Enquanto a implementação do PostgreSQL usa pool.query para executar uma declaração SQL UPDATE
e uma cláusulaWHERE
para atualizar o contato na tabela contacts
, a implementação do MongoDB usa o métodofindOneAndUpdate
com $set
para atualizar o documento na coletacontacts
.Excluir contato:
1 app.delete('/contacts/:id', authenticateToken, async (req, res) => { 2 const { id } = req.params; 3 const contact = await contactsCollection.deleteOne({ _id: new ObjectId(id), user_id: req.user.sub }); 4 if (!contact.deletedCount) return res.status(404).json({ message: 'Contact not found or not authorized' }); 5 res.status(200).json(contact.value); 6 });
Esse endpoint é o equivalente do MongoDB do endpoint DELETE
/contact
anterior projetado para PostgreSQL. Enquanto a implementação do PostgreSQL usa pool.query para executar uma declaração SQL DELETE
e uma cláusulaWHERE
para excluir o contato na tabelacontacts
, a implementação do MongoDB usa o métododeleteOne
para excluir o documento na collectioncontacts
collection.No MongoDB, a query é feita usando objetos semelhantes a JSON. O equivalente da cláusula ONDE é o objeto de query passado para métodos como findOne, deleteOne etc.
Adicionar taxa de chamada:
1 app.post('/contacts/:id/rates', authenticateToken, async (req, res) => { 2 const { id } = req.params; 3 const { description } = req.body; 4 const rate = { description, createdAt: new Date().toISOString(), user_id: new ObjectId(req.user.id) }; 5 const result = await contactsCollection.updateOne( 6 { _id: new ObjectId(id), user_id: req.user.sub }, 7 { $push: { rates: rate } } 8 ); 9 if (result.matchedCount === 0) return res.status(404).json({ message: 'Contact not found ' }); 10 res.status(201).json(rate); 11 });
Esse endpoint é o equivalente do MongoDB do endpoint POST
/contacts/:id/rates
anterior projetado para PostgreSQL. Enquanto a implementação do PostgreSQL usa pool.query
para executar uma declaração SQL INSERT INTO
para inserir uma linha de taxa na tabela, a implementação do MongoDB usa o contactsCollection.updateOne
para adicionar uma taxa a um contato, que agora atualizará o documento de contato enviando um nova taxa na array de taxas incorporada.Ao incorporar as taxas nos contatos, você evita a necessidade de junções (como
$lookup
), o que pode melhorar o desempenho da consulta, especialmente para operações de leitura pesada. Agora, todas as informações relevantes sobre um contato, incluindo suas taxas, são armazenadas juntas em um único documento.Obter contatos:
1 app.get("/contacts", authenticateToken, async (req, res) => { 2 let { startDate, endDate } = req.query; 3 4 if (!endDate) { 5 endDate = new Date().toISOString(); 6 } else { 7 endDate = new Date(endDate).toISOString(); 8 } 9 10 if (!startDate) { 11 const now = new Date(); 12 const pastDate = new Date(now); 13 pastDate.setDate(now.getDate() - 7); 14 15 startDate = pastDate.toISOString(); 16 } else { 17 startDate = new Date(startDate).toISOString(); 18 } 19 20 const contacts = await contactsCollection 21 .aggregate([ 22 { 23 $match: { 24 createdAt: { 25 $gte: startDate, 26 $lte: endDate, 27 }, 28 user_id: req.user.sub 29 }, 30 }, 31 { 32 $lookup: { 33 from: "users", 34 localField: "user_id", 35 foreignField: "_id", 36 as: "user", 37 }, 38 }, 39 { 40 $addFields: { 41 call_rate: { $size: { $ifNull: ["$rates", []] } }, 42 }, 43 }, 44 { $sort: { call_rate: -1 } }, 45 ]) 46 .toArray(); 47 48 res.status(200).json(contacts); 49 });
Esse endpoint é o equivalente do MongoDB do endpoint GET anterior
/contacts
projetado para PostgreSQL. Enquanto a implementação do PostgreSQL usa uma query SQL com JOIN
declarações , WHERE
cláusula , GROUP BY
e ORDER BY
para executar operações (correspondência, união, adição de campos, classificação) na contacts
tabela , a implementação do MongoDB usa o aggregate
método para executar operações semelhantes na contacts
collection .Um pipeline de agregação no MongoDB é uma estrutura que passa documentos para um pipeline de vários estágios que pode transformá-los e gerar resultados agregados. Cada estágio do pipeline executa uma operação nos documentos de entrada e passa o resultado para o próximo estágio.
Esse pipeline de agregação filtra os contatos com base em sua data de criação e no ID do usuário autenticado, une a collection de contatos à collection de usuários para buscar detalhes do usuário, une a collection de contatos à collection de taxas para buscar detalhes das taxas e, em seguida, adiciona um novo campo -- - call_rate --- para contar o número de taxas por contato e classificar os contatos por call_rate em ordem decrescente.
Em comparação com a declaração SQL, você não precisa usar dois JOINs. Portanto, o desempenho é melhor.
Agora, vamos falar sobre como usar o Conversor de query do MongoDB para migrar suas queries SQL para a API de query do MongoDB.
O MongoDB fornece uma ferramenta chamada Relational Migrator que permite migrar suas queries SQL para a API de query do MongoDB com facilidade. Ele também aborda desafios comuns de migração e modelagem de dados para fornecer uma transição suave para o MongoDB.
Baixar o Relational Migrator para experimentar você mesmo.
Antes de utilizar o conversor de query, você deve iniciar sessão na sua conta Atlas no Relational Migrator. Para detalhes, consulte Iniciar sessão com Atlas.
- Abra a aplicação Relational Migrator no seu PC e inicie sessão com Atlas.
- Conecte-se ao seu banco de dados Postgres.
- Selecione as tabelas que deseja migrar.
- Defina seu esquema da seguinte forma:
Em seguida, nomeie seu projeto.
Gere o esquema MongoDB a partir da tabela do banco de dados Postgres importada da seguinte forma:
Na aba Geração de código, clique no painel Conversor de query.
Clique no botão Colar query SQL para acessar o editor do conversor de query.
Aqui, você pode inserir as queries SQL que deseja converter e clicar em Converter para convertê-las em queries do MongoDB.
O MongoDB Compass é uma interface gráfica de usuário para MongoDB e é totalmente gratuito para instalar no Mac, Windows e Linux. Você pode importar dados JSON ou CSV para o MongoDB via MongoDB Compass.
Para importar dados para uma collection, conecte-se ao cluster de banco de dados usando a connection string do Atlas, crie um banco de dados e uma collection, e navegue até a exibição detalhada da collection selecionando a collection na aba Bancos de dados ou clicando na collection na navegação do lado esquerdo .
Em seguida, clique no menu suspenso Adicionar Dados, selecione Importar arquivo JSON ou CSV, selecione o tipo de arquivo apropriado e clique em Importar. Após a importação bem-sucedida, a caixa de diálogo é fechada e o Compass exibe a página de coleção que contém os documentos recém-importados.
Para importar dados usando
mongoimport
, instale as MongoDB database, um conjunto de utilitários de linha de comando para trabalhar com o MongoDB e, em seguida, execute mongoimport
a partir da linha de comando do sistema.Aqui está um exemplo de importação de dados via
mongoimport
:1 mongoimport mongodb+srv://<cluster-username>:<cluster-password>@cluster0.33t5arb.mongodb.net/Node-API?retryWrites=true&w=majority&appName=Cluster0 --collection=user --file=users.json
Aqui, usamos
mongoimport
para importar os dados JSON do arquivo users.json para a collection de usuários no banco de dados Node-API.Para importar dados usando a extensão VS Code, Go para a aba de extensões no VS Code e procure MongoDB. Você deve ver a extensão do MongoDB para VS Code.
Depois de instalá-lo com sucesso, você verá um ícone de folha na barra lateral do VS Code. Clique nele e, em conexões, adicione uma nova conexão. Em seguida, clique em Conectar com a cadeia de conexão e passe a cadeia de conexão do cluster de banco de dados.
Você deve ver seu cluster. Passe o mouse sobre seu cluster e clique no ícone de "mais" para criar um novo banco de dados. Isso gerará um arquivo de playground onde você pode adicionar o seguinte script para criar um banco de dados, collection e importar dados:
1 // Select the database to use. 2 use('database-name'); 3 // Insert documents into the users collection. 4 db.getCollection('users').insertMany("Copy and paste the content of your JSON file here");
Use o Postman ou qualquer ferramenta de teste da API para testar todos os endpoints atualizados com as queries migradas e garantir que a migração funcione conforme o esperado.
A migração de um aplicativo Node.js de um banco de dados SQL para o MongoDB pode ser simples e eficiente quando feita com um recurso bem estruturado. Neste tutorial, demos uma olhada em configurar o MongoDB, migrar as queries SQL e executar a migração de dados com o MongoDB Compass, MongoImport e a extensão MongoDB for VS Code.
Seguindo a abordagem estruturada no tutorial, você pode migrar com sucesso seu aplicativo Node.js de um banco de dados SQL para o MongoDB.
Perguntas? Quer compartilhar o que você está construindo?Em seguida, acesse a Comunidade de desenvolvedores doMongoDB.
Principais comentários nos fóruns
Ainda não há comentários sobre este artigo.