Node.js é uma plataforma que permite a você construir aplicações server-side em JavaScript, já falei disso extensivamente neste artigo.
MongoDB é um banco de dados NoSQL, orientado a documentos JSON(-like), o mesmo formato de dados usado no JavaScript, além de ser utilizado através de funções com sintaxe muito similar ao JS também, diferente dos bancos SQL tradicionais e também já falei disso extensivamente neste artigo.
Vê algo em comum entre os dois? Pois é, ambos tem o JavaScript em comum e isso facilita bastante o uso destas duas tecnologias em conjunto, motivo de ser uma dupla bem frequente para projetos de todos os tamanhos.
A ideia deste tutorial é justamente lhe dar um primeiro contato prático com ambos, fazendo o famoso CRUD (Create, Retrieve, Update e Delete).
Neste artigo você vai ver:
- Configurando o Node.js
- Configurando o MongoDB
- Conectando no MongoDB com Node
- Cadastrando no banco
- Atualizando clientes
- Excluindo clientes
Vamos lá!
#1 – Configurando o Node.js
Vamos começar instalando o Node.js: apenas clique no link do site oficial e depois no grande botão verde para baixar o executável certo para o seu sistema operacional (recomendo a versão LTS). Esse executável irá instalar o Node.js e o NPM, que é o gerenciador de pacotes do Node. Caso tenha dificuldade, o vídeo abaixo pode ajudar.
Uma vez com o NPM instalado, vamos instalar o módulo que será útil mais pra frente. Crie uma pasta para guardar os seus projetos Node no computador (recomendo C:\node) e dentro dela, via terminal de comando com permissão de administrador (sudo no Mac/Linux), rode o comando abaixo:
1
|
npm install -g express-generator
|
O Express é o web framework mais famoso da atualidade para Node.js. Com ele você consegue criar aplicações e APIs web muito rápida e facilmente. O que instalamos é o express-generator, um gerador de aplicação de exemplo, que podemos usar via linha de comando, da seguinte maneira:
1
|
express -e –git node-mongo-crud
|
O “-e” é para usar a view-engine (motor de renderização) EJS, ao invés do tradicional Jade/Pug. Já o “–git” deixa seu projeto preparado para versionamento com Git. Aperte Enter e o projeto será criado (talvez ele peça uma confirmação, apenas digite ‘y’ e confirme).
Depois entre na pasta e mande instalar as dependências com npm install:
1
2
|
cd node-mongo-crud
npm install
|
Ainda no terminal de linha de comando e, dentro da pasta do projeto, digite:
1
|
npm start
|
Isso vai fazer com que a aplicação default inicie sua execução em localhost:3000, que você pode acessar pelo seu navegador.
#2 – Configurando o MongoDB
OK, agora que temos a estrutura básica vamos fazer mais alguns ajustes em um arquivo que fica na raiz do seu projeto chamado package.json. Ele é o arquivo de configuração do seu projeto e determina, por exemplo, quais as bibliotecas que você possui dependência no seu projeto.
Vamos agora acessar o site oficial do MongoDB e baixar o Mongo. Clique no menu superior em Products > MongoDB Community Edition > MongoDB Community Server e busque a versão mais recente para o seu sistema operacional. Baixe o arquivo e, no caso do Windows, rode o executável que extrairá os arquivos na sua pasta de Arquivos de Programas, o que é está ok para a maioria dos casos.
Dentro da pasta do seu projeto Node, que aqui chamei de workshoptdc, deve existir uma subpasta de nome data, crie ela agora. Nesta pasta vamos armazenar nossos dados do MongoDB.
Pelo prompt de comando, entre na subpasta bin dentro da pasta de instalação do seu MongoDB e digite (no caso de Mac e Linux, coloque um ./ antes do mongod e ajuste o caminho da pasta data de acordo):
1
|
mongod –dbpath c:\node-mongo-crud\data
|
Isso irá iniciar o servidor do Mongo. Se não der nenhum erro no terminal, o MongoDB está pronto e está executando corretamente.
Agora o cliente que eu recomendo é o MongoDB Compass, que você também baixa pelo site oficial em Products > Tools > MongoDb Compass, sendo que o vídeo abaixo ilustra bem como funciona a ferramenta, caso queira um rápido overview.
Após a conexão funcionar do MongoDb Compass com o seu servidor de MongoDB, você deve criar uma nova database indo no menu lateral e escolhendo a opção Databaes > Create Database. Vou usar como nome da base workshoptdc e já vou aproveitar e informar o nome da coleção principal que é customer (clientes em inglês).
Uma de minhas coisas favoritas sobre MongoDB é que ele usa JSON como estrutura de dados, o que significa curva de aprendizagem zero para quem já conhece o padrão. Caso não seja o seu caso, terá que buscar algum tutorial de JSON na Internet antes de prosseguir.
Vamos adicionar um registro à nossa coleção (o equivalente do Mongo às tabelas do SQL). Para este tutorial teremos apenas uma base de customers (clientes), sendo o nosso formato de dados como abaixo:
1
2
3
4
5
|
{
“_id” : ObjectId(“1234”),
“name” : “luiztools”,
“age” : 32
}
|
O atributo _id pode ser omitido, neste caso o próprio Mongo gera um id pra você. No MongoDb Compass, entre na base workshoptdc e depois na coleção customers para ter acesso à opção “Add Data” e em seguida “Insert Document”.
Na tela que vai se abrir, adicione um JSON de cliente com o nome de Luiz e a idade de 34. Ou os dados que julgar melhores, sendo que o _id pode ser omitido pois vai ser gerado dinamicamente.
1
2
3
4
|
{
“name”: “Luiz”,
“age”: 34
}
|
Após inserir, automaticamente a listagem da ferramenta se atualiza mostrando o registro recém inserido. Adicione alguns registros para ter uma base mínima para o desenvolvimento e agora sim, vamos interagir de verdade com o web server + MongoDB.
#3 – Conectando no MongoDB com Node
Agora sim vamos juntar as duas tecnologias-alvo deste post!
Precisamos adicionar uma dependência para que o MongoDB funcione com essa aplicação usando o driver nativo. Usaremos o NPM via linha de comando de novo:
1
|
npm install mongodb dotenv
|
Com isso, duas dependências novas serão baixadas para sua pasta node_modules e duas novas linhas de dependências serão adicionadas no package.json para dar suporte a MongoDB e a variáveis de ambiente (com DotEnv). As variáveis de ambiente precisam ser a primeira coisa a serem carregadas quando a aplicação subir. Então vá no arquivo bin/www e adicione essa linha bem no topo.
1
|
require(“dotenv”).config();
|
Essa instrução irá procurar um arquivo de variáveis de ambiente na raiz do seu projeto, que você deve criar com o nome .env e o seguinte conteúdo.
1
2
|
MONGO_HOST=mongodb://127.0.0.1:27017
MONGO_DATABASE=workshoptdc
|
A variável MONGO_HOST é o endereço do seu servidor de MongoDB (use IP, nunca localhost), enquanto que a variável MONGO_DATABASE é o nome da sua base de dados, então altere conforme julgar necessário.
Agora, para organizar nosso acesso à dados, vamos criar um novo arquivo chamado db.js na raiz da nossa aplicação Express (workshoptdc). Esse arquivo será o responsável pela conexão e manipulação do nosso banco de dados, usando o driver nativo do MongoDB. Adicione estas linhas:
1
2
3
4
5
6
7
8
9
10
11
12
13
|
const { MongoClient, ObjectId } = require(“mongodb”);
let singleton;
async function connect() {
if (singleton) return singleton;
const client = new MongoClient(process.env.MONGO_HOST);
await client.connect();
singleton = client.db(process.env.MONGO_DATABASE);
return singleton;
}
|
Estas linhas carregam um objeto cliente de conexão a partir do módulo ‘mongodb’ e depois fazem uma conexão em nosso banco de dados. Essa conexão é armazenada em uma variável global do módulo. A última linha ignore por enquanto, usaremos ela mais tarde.
A seguir, vamos modificar a nossa rota para que ela mostre dados vindos do banco de dados, usando esse db.js que acabamos de criar.
Para conseguirmos fazer uma listagem de clientes, o primeiro passo é ter uma função que retorne todos os clientes em nosso módulo db.js (arquivos JS que criamos são chamados de módulos se possuírem um module.exports no final), assim, adicione a seguinte função ao seu db.js (substituindo aquela linha do module.exports que tinha antes):
1
2
3
4
5
6
7
8
|
const COLLECTION = “customers”;
async function findAll() {
const db = await connect();
return db.collection(COLLECTION).find().toArray();
}
module.exports = { findAll }
|
A consulta aqui é bem direta: usamos a função que criamos antes, connect, para obter a conexão e depois navegamos até a collection de customers e fazemos um find sem filtro algum. O resultado desse find é um cursor, então usamos o toArray para convertê-lo para um array e retorná-lo.
Repare na última instrução, ela diz que a nossa função findAll poderá ser usada em outros pontos da nossa aplicação que importem nosso módulo db:
1
|
module.exports = { findAll }
|
Agora vamos programar a lógica que vai usar esta função. Abra o arquivo ./routes/index.js no seu editor de texto (sugiro o Visual Studio Code). Dentro dele temos apenas a rota default, que é um get no path raiz. Vamos editar essa rota da seguinte maneira (atenção ao carregamento do módulo db.js no topo):
1
2
3
4
5
6
7
8
9
10
11
|
const db = require(“../db”);
/* GET home page. */
router.get(‘/’, async (req, res, next) => {
try {
const docs = await db.findAll();
res.render(‘index’, { title: ‘Lista de Clientes’, docs });
} catch (err) {
next(err);
}
})
|
router.get define a rota que trata essas requisições com o verbo GET. Quando recebemos um GET /, a função de callback dessa rota (aquela com req, res e next) é disparada e com isso usamos o findAll que acabamos de programar. Como esta é uma função assíncrona que vai no banco de dados, precisamos usar a palavra reservada await antes dela, ter um try/catch para tratar seus possíveis erros e o callback do router tem de ter a palavra async antes dos parâmetros da função.
Foge um pouco do escopo deste tutorial explicar programação assíncrona em Node.js, então recomendo o vídeo abaixo se quiser entender mais do assunto.
Agora vamos arrumar a nossa view para listar os clientes. Entre na pasta ./views/ e edite o arquivo index.ejs para que fique desse jeito:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
|
<!DOCTYPE html>
<html>
<head>
<title><%= title %></title>
<link rel=‘stylesheet’ href=‘/stylesheets/style.css’ />
</head>
<body>
<h1><%= title %></h1>
<ul>
<% docs.forEach(function(customer){ %>
<li>
<%= customer.name %>
</li>
<% }) %>
</ul>
</body>
</html>
|
Aqui estamos dizendo que o objeto docs, que será retornado pela rota que criamos no passo anterior, será iterado com um forEach e seus objetos utilizados um-a-um para compor uma lista não-ordenada com seus nomes.
Isto é o bastante para a listagem funcionar. Para não ter que ficar derrubando e subindo novamente a sua aplicação toda hora, modifique o script de start no seu package.json para:
1
2
3
|
“scripts”: {
“start”: “npx nodemon ./bin/www”
},
|
Agora suba com npm start novamente e toda vez que fizer novas alterações, elas serão carregadas automaticamente por causa da extensão nodemon, que eu falo mais a respeito no vídeo abaixo.