Atualizado: 02/01/2025

Express e MongoDB - Node.js

Em uma única aplicação, vamos unir o processamento de solicitações com o Express e o trabalho com dados no MongoDB. Para isso, definiremos o seguinte arquivo de aplicação app.js:

const express = require("express");
const MongoClient = require("mongodb").MongoClient;
const objectId = require("mongodb").ObjectId;

const app = express();
app.use(express.static("public"));  // arquivos estáticos estarão na pasta public
app.use(express.json());  // ativamos o parsing automático de JSON

const mongoClient = new MongoClient("mongodb://127.0.0.1:27017/");

(async () => {
    try {
        await mongoClient.connect();
        app.locals.collection = mongoClient.db("usersdb").collection("users");
        app.listen(3000, () => console.log("Servidor iniciado em http://localhost:3000"));
    } catch(err) {
        console.log(err);
    } 
})();

app.get("/api/users", async(req, res) => {
    const collection = req.app.locals.collection;
    try {
        const users = await collection.find({}).toArray();
        res.send(users);
    } catch(err) {
        console.log(err);
        res.sendStatus(500);
    }
});

app.get("/api/users/:id", async(req, res) => {
    const collection = req.app.locals.collection;
    try {
        const id = new objectId(req.params.id);
        const user = await collection.findOne({_id: id});
        if (user) res.send(user);
        else res.sendStatus(404);
    } catch(err) {
        console.log(err);
        res.sendStatus(500);
    }
});

app.post("/api/users", async(req, res) => {
    if (!req.body) return res.sendStatus(400);

    const userName = req.body.name;
    const userAge = req.body.age;
    const user = {name: userName, age: userAge};

    const collection = req.app.locals.collection;

    try {
        await collection.insertOne(user);
        res.send(user);
    } catch(err) {
        console.log(err);
        res.sendStatus(500);
    }
});

app.delete("/api/users/:id", async(req, res) => {
    const collection = req.app.locals.collection;
    try {
        const id = new objectId(req.params.id);
        const user = await collection.findOneAndDelete({_id: id});
        if (user) res.send(user);
        else res.sendStatus(404);
    } catch(err) {
        console.log(err);
        res.sendStatus(500);
    }
});

app.put("/api/users", async(req, res) => {
    if (!req.body) return res.sendStatus(400);

    const userName = req.body.name;
    const userAge = req.body.age;

    const collection = req.app.locals.collection;
    try {
        const id = new objectId(req.body.id);
        const user = await collection.findOneAndUpdate({_id: id}, { $set: {age: userAge, name: userName}}, {returnDocument: "after" });
        if (user) res.send(user);
        else res.sendStatus(404);
    } catch(err) {
        console.log(err);
        res.sendStatus(500);
    }
});

// escutando a interrupção do programa (ctrl-c)
process.on("SIGINT", async() => {
    await mongoClient.close();
    console.log("Aplicação encerrada");
    process.exit();
});

Para cada tipo de solicitação, há um manipulador específico do Express. Em cada manipulador, acessamos o banco de dados. Para evitar abrir e fechar a conexão a cada solicitação, abrimos a conexão no início com uma função IIFE ( Imediately Invoked Function Expression) e só depois de abrir a conexão, iniciamos a escuta de solicitações:

(async () => {
    try {
        await mongoClient.connect();
        app.locals.collection = mongoClient.db("usersdb").collection("users");
        app.listen(3000, () => console.log("Servidor iniciado em http://localhost:3000"));
    } catch(err) {
        console.log(err);
    }
})();

Como toda a interação será com a coleção users, obtemos uma referência a esta coleção na variável local da aplicação app.locals.collection. Depois, através dessa variável, podemos acessar a coleção em qualquer parte da aplicação.

No final do script, podemos fechar a conexão armazenada na variável mongoClient:

process.on("SIGINT", async() => {
  await mongoClient.close();
  console.log("Aplicação encerrada");
  process.exit();
});

Neste caso, ouvimos o evento "SIGINT", que é disparado ao pressionar a combinação CTRL+C no console, encerrando a execução do script.

Quando uma solicitação GET é enviada à aplicação, retornamos todos os documentos da coleção users:

app.get("/api/users", async(req, res) => {
  const collection = req.app.locals.collection;
  try {
      const users = await collection.find({}).toArray();
      res.send(users);
  } catch(err) {
      console.log(err);
      res.sendStatus(500);
  }
});

Se um parâmetro id for passado na solicitação GET, retornamos apenas um usuário do banco de dados com este id:

app.get("/api/users/:id", async(req, res) => {
  const collection = req.app.locals.collection;
  try {
      const id = new objectId(req.params.id);
      const user = await collection.findOne({_id: id});
      if (user) res.send(user);
      else res.sendStatus(404);
  } catch(err) {
      console.log(err);
      res.sendStatus(500);
  }
});

Quando uma solicitação POST é recebida, usamos o parser JSON para obter os dados enviados e, com eles, criamos um objeto que adicionamos ao banco de dados através do método insertOne():

app.post("/api/users", async(req, res) => {
  if (!req.body) return res.sendStatus(400);

  const userName = req.body.name;
  const userAge = req.body.age;
  const user = {name: userName, age: userAge};

  const collection = req.app.locals.collection;

  try {
      await collection.insertOne(user);
      res.send(user);
  } catch(err) {
      console.log(err);
      res.sendStatus(500);
  }
});

Quando recebemos uma solicitação PUT, também obtemos os dados enviados e usamos o método findOneAndUpdate() para atualizar os dados no banco de dados.

No método app.delete(), acionado ao receber uma solicitação DELETE, chamamos o método findOneAndDelete() para excluir os dados.

Assim, em cada manipulador do Express, usamos um método específico para trabalhar com o MongoDB.

Definindo o Código em index.html

Agora, criaremos uma nova pasta chamada public no diretório do projeto e definiremos nela o arquivo index.html.

mongoapp/
│
├── node_modules/
│
├── public/
│   └── index.html
│
├── app.js
├── package.json
└── package-lock.json 

No arquivo index.html, definiremos o seguinte código:

<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8" />
    <meta name="viewport" content="width=device-width" />
    <title>Programício</title>
    <style>
        td, th {padding: 5px; min-width: 90px; max-width: 200px; text-align: start;}
        .btn {padding: 4px; border: 1px solid #333; background-color: #eee; border-radius: 2px; margin: 5px; cursor: pointer;}
    </style>
</head>
<body>
    <h2>Lista de Usuários</h2>
    <form name="userForm">
        <input type="hidden" name="id" value="0" />
        <p>
            <label>Nome:</label><br>
            <input name="name" />
        </p>
        <p>
            <label>Idade:</label><br>
            <input name="age" type="number" />
        </p>
        <p>
            <button id="submitBtn" type="submit">Salvar</button>
            <button id="resetBtn">Resetar</button>
        </p>
    </form>
    <table>
        <thead>
            <tr><th>Id</th><th>Nome</th><th>Idade</th><th></th></tr>
        </thead>
        <tbody></tbody>
    </table>
    <script>
        const tbody = document.querySelector("tbody");

        // Obtendo todos os usuários
        async function getUsers() {
            const response = await fetch("/api/users", {
                method: "GET",
                headers: { "Accept": "application/json" }
            });

            if (response.ok === true) {
                const users = await response.json(); 
                users.forEach(user => {
                    tbody.append(row(user));
                });
            }
        }

        // Obtendo um usuário
        async function getUser(id) {
            const response = await fetch("/api/users/" + id, {
                method: "GET",
                headers: { "Accept": "application/json" }
            });
            if (response.ok === true) {
                const user = await response.json();
                const form = document.forms["userForm"];
                form.elements["id"].value = user._id;
                form.elements["name"].value = user.name;
                form.elements["age"].value = user.age;
            }
        }

        // Adicionando um usuário
        async function createUser(userName, userAge) {
            const response = await fetch("api/users", {
                method: "POST",
                headers: { "Accept": "application/json", "Content-Type": "application/json" },
                body: JSON.stringify({
                    name: userName,
                    age: parseInt(userAge, 10)
                })
            });
            if (response.ok === true) {
                const user = await response.json();
                reset();
                tbody.append(row(user));
            }
        }

        // Editando um usuário
        async function editUser(userId, userName, userAge) {
            const response = await fetch("api/users", {
                method: "PUT",
                headers: { "Accept": "application/json", "Content-Type": "application/json" },
                body: JSON.stringify({
                    id: userId,
                    name: userName,
                    age: parseInt(userAge, 10)
                })
            });
            if (response.ok === true) {
                const user = await response.json();
                reset();
                document.querySelector(`tr[data-rowid="${user._id}"]`).replaceWith(row(user));
            }
        }

        // Excluindo um usuário
        async function deleteUser(id) {
            const response = await fetch("/api/users/" + id, {
                method: "DELETE",
                headers: { "Accept": "application/json" }
            });
            if (response.ok === true) {
                const user = await response.json();
                document.querySelector(`tr[data-rowid="${user._id}"]`).remove();
            }
        }

        // Resetando o formulário
        function reset() {
            const form = document.forms["userForm"];
            form.reset();
            form.elements["id"].value = 0;
        }

        // Criando uma linha para a tabela
        function row(user) {
            const tr = document.createElement("tr");
            tr.setAttribute("data-rowid", user._id);

            const idTd = document.createElement("td");
            idTd.append(user._id);
            tr.append(idTd);

            const nameTd = document.createElement("td");
            nameTd.append(user.name);
            tr.append(nameTd);

            const ageTd = document.createElement("td");
            ageTd.append(user.age);
            tr.append(ageTd);

            const linksTd = document.createElement("td");

            const editLink = document.createElement("a");
            editLink.setAttribute("data-id", user._id);
            editLink.setAttribute("class", "btn");
            editLink.append("Editar");
            editLink.addEventListener("click", e => {
                e.preventDefault();
                getUser(user._id);
            });
            linksTd.append(editLink);

            const removeLink = document.createElement("a");
            removeLink.setAttribute("data-id", user._id);
            removeLink.setAttribute("class", "btn");
            removeLink.append("Excluir");
            removeLink.addEventListener("click", e => {
                e.preventDefault();
                deleteUser(user._id);
            });

            linksTd.append(removeLink);
            tr.appendChild(linksTd);

            return tr;
        }

        // Resetando os valores do formulário
        document.getElementById("resetBtn").addEventListener("click", e => {
            e.preventDefault();
            reset();
        });

        // Enviando o formulário
        document.forms["userForm"].addEventListener("submit", e => {
            e.preventDefault();
            const form = document.forms["userForm"];
            const id = form.elements["id"].value;
            const name = form.elements["name"].value;
            const age = form.elements["age"].value;
            if (id == 0)
                createUser(name, age);
            else
                editUser(id, name, age);
        });

        // Carregando os usuários
        getUsers();
    </script>
</body>
</html>

O código deste arquivo já foi explicado no tema sobre API em Node.js, e aqui ele é praticamente o mesmo.

Neste arquivo, definimos um formulário e uma tabela para gerenciar os usuários armazenados no banco de dados MongoDB. O código JavaScript no arquivo permite buscar, adicionar, editar e excluir usuários através de chamadas à API do Node.js que definimos anteriormente.

Como o Express usa a pasta public para armazenar arquivos estáticos, ao acessar a aplicação pela rota raiz http://localhost:3000, o cliente receberá este arquivo.

Vamos iniciar a aplicação, acessar http://localhost:3000 e poderemos gerenciar os usuários armazenados no banco de dados MongoDB:

Express e MongoDB em Node.js
Política de Privacidade

Copyright © www.programicio.com Todos os direitos reservados

É proibida a reprodução do conteúdo desta página sem autorização prévia do autor.

Contato: programicio@gmail.com