Node JS puede ser conectado a PostgreSQL fácilmente a través del paquete pg.
En este tutorial vamos a ver cómo conectar Node.JS con PostgreSQL y hacer las cuatro operaciones básicas de la base de datos: Create, read, update y delete (CRUD); todo esto evitando inyecciones SQL y usando un poco el model MVC.
Para la interfaz vamos a usar Bootstrap (ya que será responsivo), y para que el usuario use nuestra app web vamos a usar Express.
Aunque estos ejemplos son con la web, los mismos pueden ser ejecutados en la terminal sin ningún problema.
Recuerda instalar Node.JS y también PostgreSQL.
Si no sabes mucho sobre Express, te recomiendo leer primero este post o este otro que usa express-generator.
¿Te gusta más MySQL? mira este CRUD con MySQL y Node.js
En el código que dejaré al final estará el package,json en donde están todas las dependencias de la app, sin embargo nunca sobra dejar el comando de instalación:
npm install --save pg
Vamos a conectarnos a una tabla de productos que tienen id autoincrementable, nombre y precio.
La estructura de la tabla es la siguiente:
create table productos(
id serial primary key,
nombre varchar(255),
precio decimal(5, 2)
);
Nos vamos a conectar a través de ella creando una conexión a través de un pool. No olvides cambiar tus credenciales de acuerdo a tu configuración.
Si necesitas crear una base de datos con usuarios mira este post.
const { Pool } = require("pg")
// Coloca aquí tus credenciales
const pool = new Pool({
user: "postgres",
host: "127.0.0.1",
database: "tienda",
password: "hunter2",
port: 5432,
});
module.exports = pool;
Cuando establecemos una conexión con la base de datos podemos llamar al método query con la consulta como cadena y opcionalmente un arreglo de valores que van a remplazar a los placeholders.
El placeholder es aquel indicado con $1
, $2
, etcétera y evita las inyecciones SQL. En los ejemplos veremos su uso.
Por cierto, vamos a usar async y await, una manera sencilla de abstraer las promesas.
Basta de charlas, es hora de ver el modelo de productos que se encargará de interactuar con la base de datos:
const conexion = require("../conexion")
module.exports = {
async insertar(nombre, precio) {
let resultados = await conexion.query(`insert into productos
(nombre, precio)
values
($1, $2)`, [nombre, precio]);
return resultados;
},
async obtener() {
const resultados = await conexion.query("select id, nombre, precio from productos");
return resultados.rows;
},
async obtenerPorId(id) {
const resultados = await conexion.query(`select id, nombre, precio from productos where id = $1`, [id]);
return resultados.rows[0];
},
async actualizar(id, nombre, precio) {
const resultados = conexion.query(`update productos
set nombre = $1,
precio = $2
where id = $3`, [nombre, precio, id]);
return resultados;
},
async eliminar(id) {
const resultados = conexion.query(`delete from productos
where id = $1`, [id]);
return resultados;
},
}
Cuando hacemos una consulta que devuelve datos, los mismos vienen en la propiedad rows
.
Si solo vamos a obtener un dato, accedemos a rows[0]
.
Voy a usar el enrutador como controlador, pues se encargará de renderizar las vistas y pasarle datos a través de los modelos.
Si no sabes mucho sobre las rutas mira este post.
const express = require('express');
const router = express.Router();
const productosModel = require("../models/productos");
router.get('/', function (req, res, next) {
productosModel
.obtener()
.then(productos => {
console.log(productos);
res.render("productos/ver", {
productos: productos,
});
})
.catch(err => {
console.log(err);
return res.status(500).send("Error obteniendo productos");
});
});
router.get('/agregar', function (req, res, next) {
res.render("productos/agregar");
});
router.post('/insertar', function (req, res, next) {
// Obtener el nombre y precio. Es lo mismo que
// const nombre = req.body.nombre;
// const precio = req.body.precio;
const { nombre, precio } = req.body;
if (!nombre || !precio) {
return res.status(500).send("No hay nombre o precio");
}
// Si todo va bien, seguimos
productosModel
.insertar(nombre, precio)
.then(idProductoInsertado => {
res.redirect("/productos");
})
.catch(err => {
return res.status(500).send("Error insertando producto");
});
});
router.get('/eliminar/:id', function (req, res, next) {
productosModel
.eliminar(req.params.id)
.then(() => {
res.redirect("/productos");
})
.catch(err => {
return res.status(500).send("Error eliminando");
});
});
router.get('/editar/:id', function (req, res, next) {
productosModel
.obtenerPorId(req.params.id)
.then(producto => {
if (producto) {
res.render("productos/editar", {
producto: producto,
});
} else {
return res.status(500).send("No existe producto con ese id");
}
})
.catch(err => {
return res.status(500).send("Error obteniendo producto");
});
});
router.post('/actualizar/', function (req, res, next) {
// Obtener el nombre y precio. Es lo mismo que
// const nombre = req.body.nombre;
// const precio = req.body.precio;
const { id, nombre, precio } = req.body;
if (!nombre || !precio || !id) {
return res.status(500).send("No hay suficientes datos");
}
// Si todo va bien, seguimos
productosModel
.actualizar(id, nombre, precio)
.then(() => {
res.redirect("/productos");
})
.catch(err => {
return res.status(500).send("Error actualizando producto");
});
});
module.exports = router;
Como ves, algunas rutas se encargan de renderizar vistas y otras de recuperar datos del formulario. Para pasar datos a las vistas se pasa un objeto como segundo argumento a res.render
.
Las vistas son creadas con EJS, aunque pueden ser creadas con cualquier otro motor de plantillas. Comencemos viendo el encabezado y el pie, pues serán unas cosas que siempre vamos a incluir en todas las demás plantillas.
Recuerda que está basado en una plantilla de Bootstrap 4.
<!doctype html>
<html lang="es">
<!--
Plantilla inicial de Bootstrap 4
@author parzibyte
Visita: parzibyte.me/blog
-->
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
<meta name="description" content="Conexión PostgreSQL y Node usando Express y Bootstrap">
<meta name="author" content="Parzibyte">
<title>Conexión PostgreSQL y Node usando Express y Bootstrap</title>
<!-- Cargar el CSS de Boostrap-->
<link href="/stylesheets/bootstrap.min.css" rel="stylesheet">
<!-- Cargar estilos propios -->
<link href="/stylesheets/style.css" rel="stylesheet">
</head>
<body>
<!-- Definición del menú -->
<nav class="navbar navbar-expand-md navbar-dark bg-dark fixed-top">
<a class="navbar-brand" target="_blank" href="//parzibyte.me/blog">Node y PGSQL - By Parzibyte</a>
<button aria-label="Mostrar u ocultar menú" class="navbar-toggler" id="botonMenu" type="button">
<span class="navbar-toggler-icon"></span>
</button>
<div class="collapse navbar-collapse" id="menu">
<ul class="navbar-nav mr-auto">
<li class="nav-item">
<a class="nav-link" href="/productos">Ver</a>
</li>
<li class="nav-item">
<a class="nav-link" href="/productos/agregar">Agregar</a>
</li>
</ul>
</div>
</nav>
<script type="text/javascript">
// Tomado de https://github.com/parzibyte/cotizaciones_web/blob/master/js/cotizaciones.js#L2
document.addEventListener("DOMContentLoaded", () => {
const menu = document.querySelector("#menu"),
botonMenu = document.querySelector("#botonMenu");
if (menu) {
botonMenu.addEventListener("click", () => menu.classList.toggle("show"));
}
});
</script>
<!-- Termina la definición del menú -->
<main role="main" class="container">
<div class="row">
</div>
</main>
</body>
</html>
El formulario para insertar datos es el siguiente, fíjate en el atributo name que tiene cada input, pues a él accedemos desde el router de express.
<%- include("../header"); %>
<div class="col-12">
<h1>Agregar producto</h1>
<form method="post" action="/productos/insertar">
<div class="form-group">
<label for="nombre">Nombre</label>
<input required id="nombre" placeholder="Nombre del producto" class="form-control" type="text"
name="nombre">
</div>
<div class="form-group">
<label for="precio">Precio</label>
<input required id="precio" placeholder="Precio del producto" class="form-control" type="number"
name="precio">
</div>
<div class="form-group">
<button class="btn btn-success">Guardar</button>
<a href="/productos" class="btn btn-primary">Volver</a>
</div>
</form>
</div>
<%- include("../footer"); %>
Para editar, debemos obtener el id producto de la URL, obtenerlo desde nuestro modelo y después rellenar el formulario.
<%- include("../header"); %>
<div class="col-12">
<h1>Editar producto</h1>
<form method="post" action="/productos/actualizar">
<input value="<%= producto.id %>" name="id" type="hidden">
<div class="form-group">
<label for="nombre">Nombre</label>
<input value="<%= producto.nombre %>" required id="nombre" placeholder="Nombre del producto"
class="form-control" type="text" name="nombre">
</div>
<div class="form-group">
<label for="precio">Precio</label>
<input value="<%= producto.precio %>" required id="precio" placeholder="Precio del producto"
class="form-control" type="number" name="precio">
</div>
<div class="form-group">
<button class="btn btn-success">Guardar</button>
<a href="/productos" class="btn btn-primary">Volver</a>
</div>
</form>
</div>
<%- include("../footer"); %>
Para mostrarlos dibujamos una tabla con los detalles del producto y además dos enlaces.
Un enlace es para eliminar y otro para editar.
<%- include("../header"); %>
<div class="col-12">
<h1>Productos</h1>
<a href="/productos/agregar" class="btn btn-primary mb-2">Agregar</a>
<table class="table table-bordered">
<thead>
<tr>
<th>Nombre</th>
<th>Precio</th>
<th>Editar</th>
<th>Eliminar</th>
</tr>
</thead>
<tbody>
<% productos.forEach(producto => { %>
<tr>
<td><%= producto.nombre %></td>
<td><%= producto.precio %></td>
<td>
<a href="/productos/editar/<%= producto.id %>" class="btn btn-warning">
Editar
</a>
</td>
<td>
<a href="/productos/eliminar/<%= producto.id %>" class="btn btn-danger">
Eliminar
</a>
</td>
</tr>
<% })%>
</tbody>
</table>
</div>
<%- include("../footer"); %>
Los enlaces parecen botones gracias a la clase btn, y a sus variantes.
Si quieres descarga el código de GitHub, asegúrate de haber instalado Node y PGSQL.
Dirígete a la carpeta del proyecto e instala las dependencias con:
npm install
Cuando se acaben de instalar ejecuta el proyecto con:
set debug=crud-postgresql-node:* & npm start
Finalmente visita localhost:3000
Node.JS y sus paquetes ayudan a que el desarrollador se centre en la lógica de la aplicación, pues solo tiene que conectar los paquetes entre sí y programar la lógica de negocio.
Dejo un enlace a la documentación oficial del paquete.
Te invito a leer más sobre Node y PostgreSQL.
El día de hoy te mostraré cómo crear un servidor HTTP (servidor web) en Android…
En este post te voy a enseñar a designar una carpeta para imprimir todos los…
En este artículo te voy a enseñar la guía para imprimir en una impresora térmica…
Hoy te voy a mostrar un ejemplo de programación para agregar un módulo de tasa…
Los usuarios del plugin para impresoras térmicas pueden contratar licencias, y en ocasiones me han…
Hoy voy a enseñarte cómo imprimir el € en una impresora térmica. Vamos a ver…
Esta web usa cookies.
Ver comentarios
Gracias ya encontré el proyecto en git
Excelente información, puedes compartir el proyecto con el código
Lea el post