¿Cómo hacer la paginación Node.js con MySQL?

Node.js es un entorno de tiempo de ejecución como el motor JavaScript V8 de Chrome. Node.js es un entorno de tiempo de ejecución back-end, multiplataforma y de código abierto que se ejecuta fuera de un navegador web.

MySQL es un sistema de administración de bases de datos relacionales de código abierto que es rápido, confiable, flexible y robusto. Tanto MySQL como Node.js son opciones de moda al crear aplicaciones web. Otra ventaja de MySQL es que proporciona soporte integrado para utilidades como la paginación.  

¿Qué es la paginación y por qué es importante?

La paginación no es más que dividir datos en partes o páginas discretas. Una página web que muestra miles de registros divididos en páginas se siente más atractiva e interactiva y mejor para el rendimiento de la aplicación. Por lo tanto, la paginación ayuda a una mejor visualización, un mejor rendimiento y una mejor experiencia del usuario al no abrumar al usuario con datos y evitar desplazamientos prolongados.  

Podemos hacer tanto la paginación del lado del cliente como la paginación del lado del servidor. En este artículo, veremos un ejemplo de paginación del lado del servidor.

Paginación del lado del servidor: según IBM, la paginación del lado del servidor es para:

  • Gran conjunto de datos.
  • Carga de página inicial más rápida.
  • Accesibilidad para aquellos que no ejecutan JavaScript.
  • Lógica empresarial de vista compleja.
  • Resiliencia a los cambios concurrentes.

La paginación del lado del servidor generalmente se realiza en el código de middleware (lógica comercial) o en la capa de la base de datos. La paginación del lado del servidor suele ser más desafiante que la del lado del cliente, pero se escala mejor.  

Paginación del lado del cliente: la paginación del lado del cliente es adecuada cuando:

  • El conjunto de datos es pequeño.
  • Cargas de página subsiguientes más rápidas
  • Los requisitos de clasificación y filtrado son totalmente compatibles (a menos que los resultados superen el tamaño máximo).

La paginación del lado del cliente es más rápida de implementar pero no es muy escalable.  

¿Pasos para hacer la paginación del lado del servidor?

Vamos a ver un ejemplo de paginación del lado del servidor. Manejaremos la paginación en el nivel de la base de datos. Para la paginación usando MySQL, necesitamos usar la Cláusula LIMIT con el valor de Compensación. La cláusula de límite recupera solo una parte de los registros. La sintaxis básica de la cláusula Limit es la siguiente:

Select <column-names>
From <table-names>
Where <conditions>
LIMIT <offset>, <number_of_records>;

El desplazamiento es opcional con un valor predeterminado de 0, pero puede obtener cualquier valor positivo menor que la cantidad de registros en el conjunto de datos.

Aplicación de ejemplo: construiremos una aplicación simple con Node.js, Express.js, MySQL y Sequelize ORM. Asegúrese de tener Node.js y MySQL en su sistema. Usaremos Visual Studio Code para desarrollar la aplicación.  

Crear una carpeta de proyecto y cambiar la carpeta

mkdir PaginationExample
cd PaginationExample

Inicializar la aplicación

npm init

Para generar el archivo package.json.

A continuación, instalamos express.js, sequelize y pug para las plantillas.

npm install -g express sequelize pug dotenv express-paginate

También requerimos instalar el paquete dotenv y express-paginate. El paquete Express-paginate expone varios métodos como href y middleware. Los detalles de las funciones se dan en la documentación.

Nuestra estructura de carpetas es la siguiente.

Estructura de la carpeta del proyecto

Para ejecutar la aplicación de Node, debemos ejecutar el siguiente comando desde la Terminal en Visual Studio Code.

node server.js

Si todo funciona correctamente, debería ver un resultado similar a este en la terminal:

Aplicación en ejecución

Una vez que vea este mensaje, puede abrir un navegador e ir al enlace: localhost:8000 

Hemos estructurado las llamadas en la aplicación, y deberíamos ver directamente una tabla con los registros y una opción para Paginar.

Página de destino de la aplicación

Código de aplicación: Veremos los archivos de código de aplicación capa por capa.

Archivo Server.js: El servidor.js es el archivo principal que contiene todas sus configuraciones relacionadas con Express y nuestra única ruta para obtener los registros y llamar al archivo de servicio. El archivo del servidor tiene el siguiente código.

Javascript

// Required External modules
const express = require("express");
const path = require("path");
require("dotenv").config();
const paginate = require("express-paginate");
 
// Required code files
const services = require("./service/services.js");
 
// Application Variables
const app = express();
const port = 8000;
 
// Server
app.listen(port, () => {
    console.log(`App running on port ${port}.`);
});
 
// Configuration
app.set("views", path.join(__dirname, "./views"));
app.set("view engine", "pug");
app.use("/static", express.static(
    path.join(__dirname, "public")));
 
app.use(paginate.middleware(10, 50));
 
// Routes
app.get("/", (req, res) => {
    const limit = req.query.limit || 10;
    const offset = req.offset;
    services.findRecords({
        offset: offset,
        limit: limit
    }).then((results) => {
        const pageCount = Math.ceil(results.count / limit);
        res.render("paginatedTable", {
            data: results.rows,
            pageCount,
            pages: paginate.getArrayPages(req)
                (3, pageCount, req.query.page),
        });
    });
});

Archivos de Sequelize: hemos separado la configuración de la base de datos, el modelo de Sequelize y la llamada en tres archivos separados para facilitar el mantenimiento a medida que la aplicación escala.  

  • El archivo de Servicios contiene todas nuestras llamadas de Sequelize.
  • models.js contiene la estructura de la tabla que usamos para nuestra consulta. Estamos usando la tabla nicer_but_slower_film_list de la base de datos SAKILA para nuestro ejemplo.
  • El archivo dbconfig.js contiene el objeto Sequelize. Todo el código relacionado con los archivos está disponible en este repositorio.
  • Sequelize proporciona un método incorporado: findAndCountAll, que es ideal para la paginación. El método findAndCountAll toma los argumentos offset y limit y devuelve el total de registros disponibles y los registros reales basados ​​en el límite y el valor de compensación. El código es el siguiente:

dbconfig.js: dbconfig contiene el objeto Sequelize. Las propiedades para crear el objeto Sequelize provienen del archivo .env según la configuración de su base de datos. Aquí hemos creado un objeto de base de datos simple.

Javascript

const Sequelize = require("sequelize");
module.exports = new Sequelize({
    dialect: "mysql",
    username: process.env.DB_USER,
    password: process.env.DB_PASS,
    host: process.env.DB_HOST,
    port: process.env.DB_PORT,
    database: process.env.DB_DATABASE,
    logging: (log) => console.log("logging:", log),
});

models.js: El archivo models.js contiene la descripción de las tablas que estamos usando en nuestras consultas. Es una representación Sequelize de las tablas de bases de datos relacionales.

Javascript

var Sequelize = require("sequelize");
db = require("../config/dbconfig.js");
 
const nicer_but_slower_film_list = db.define(
    "nicer_but_slower_film_list", {
        FID: {
            type: Sequelize.SMALLINT,
 
            // To ensure that Sequelize
            // does not use id by default
            primaryKey: true,
        },
 
        title: Sequelize.STRING,
        description: Sequelize.STRING,
        category: Sequelize.STRING,
        price: Sequelize.DECIMAL,
        length: Sequelize.SMALLINT,
        rating: Sequelize.ENUM("G", "PG", "PG-13", "R", "NC-17"),
        actors: Sequelize.STRING,
    },
    {
        // This is to ensure that Sequelize
        // does not pluralize table names
        freezeTableName: true,
 
        // This is to ensure that Sequelize
        // does not add its own timestamp
        // variables in the query.
        timestamps: false,
        createdAt: false,
        updatedAt: false,
    }
);
module.exports = nicer_but_slower_film_list;

services.js: el archivo de servicios contiene las llamadas Sequelize que realizamos. Este archivo contendría las llamadas de búsqueda, creación, actualización, eliminación de llamadas, etc. El archivo depende del objeto Sequelize (dbconfig.js) y el modelo Sequelize (models.js).  

Javascript

const Sequelize = require("sequelize");
 
// Model file
var model = require("../models/models.js");
 
// db Configuration
db = require("../config/dbconfig.js");
let findRecords = async (req, res) => {
    return model.findAndCountAll({
        offset: req.offset,
        limit: req.limit
    });
};
module.exports = { findRecords: findRecords };

Entonces, si el límite que establecemos es diez y el desplazamiento es 20 (es decir, los registros de la página 3), entonces la consulta formada por findAndCountAll y desenstringda en la base de datos es:

SELECCIONE `FID`, `título`, `descripción`, `categoría`, `precio`, `duración`, `puntuación`, `actores` FROM `mejor_pero_lenta_película_lista` AS `mejor_pero_lenta_película_lista` LÍMITE 20, 10;

La consulta da los siguientes resultados de la base de datos:

Resultados de la base de datos

La salida que se muestra en la pantalla es la siguiente:

Registros como se muestra en la interfaz de usuario de la aplicación

Interfaz de usuario de la aplicación: además de los archivos mencionados anteriormente, la estructura del proyecto también tiene la carpeta node_modules, los archivos de instalación node y express, y el archivo .env. El archivo .env contiene la información relacionada con la base de datos, como el nombre de usuario, la contraseña, el número de puerto de MySQL, etc., que usamos en el archivo dbconfig.js para crear el objeto de conexión Sequelize.

Interfaz de usuario: para manejar la interfaz de usuario, estamos utilizando la plantilla PUG. Usamos los métodos de paginación rápida para manejar los controles de paginación en la plantilla PUG. El código siguiente controla si se muestran o no los vínculos de los botones Anterior y Siguiente.

paginatedTable.pug: Esta es la interfaz de usuario con resultados paginados.

HTML

html
head 
 link(rel='stylesheet' href='https://getbootstrap.com/docs/4.4/dist/css/bootstrap.min.css')
 style 
   include ../public/style.css
body
 
h1 Movies
table
 thead
   tr
     th Title
     th Description
     th Category
     th Length
     th Rating 
     th Actors
 tbody
   each dat in data
     tr
       td  #{dat.title}
       td  #{dat.description}
       td  #{dat.category}
       td  #{dat.length}
       td  #{dat.rating}
       td  #{dat.actors}
 
 
if paginate.hasPreviousPages || paginate.hasNextPages(pageCount)
.navigation.well-sm#pagination
 ul.pager
   if paginate.hasPreviousPages
     a(href=paginate.href(true)).prev
       i.fa.fa-arrow-circle-left
       |  Previous
   if pages
     each page in pages
       a.btn.btn-default(href=page.url)= page.number
   if paginate.hasNextPages(pageCount)
     a(href=paginate.href()).next
       | Next
       i.fa.fa-arrow-circle-right
 
 script(src='https://code.jquery.com/jquery-3.4.1.slim.min.js')
 script(src='https://getbootstrap.com/docs/4.4/dist/js/bootstrap.bundle.min.js')

hasPrevious y hasNext son dos métodos expuestos por el paquete express-paginate, que devuelven valores booleanos. Según el valor de estos valores booleanos, la interfaz de usuario muestra los botones Siguiente y Anterior.

Botones Siguiente y Anterior

estilo.css

La hoja de estilo de la página es la siguiente:

CSS

table {
    width: 100%;
    border: 1px solid #fff;
    border-collapse: collapse;
    border-radius: 8px;
}
 
th,
td {
    text-align: left;
    text-transform: capitalize;
    border: 1px solid darkgrey;
    color: black;
}
 
th {
    padding: 8px 10px;
    height: 48px;
    background-color: #808e9b;
}
 
td {
    padding: 6px 8px;
    height: 40px;
}
 
a:hover {
    background-color: #555;
}
 
a:active {
    background-color: black;
}
 
a:visited {
    background-color: #ccc;
}

¿Cómo funciona exactamente la aplicación?

  • La primera vez que accedemos a la URL localhost:8000, debido al middleware de paginación rápida, el valor Límite se establece en 10 de forma predeterminada y el desplazamiento se establece en 0. Por lo tanto, los primeros diez registros se recuperan de la base de datos y se muestran.
  • Cuando el usuario pulsa el botón Siguiente o el número de página, es decir, 1, 2 o 3, el middleware de paginación calcula el desplazamiento. La fórmula para calcular el desplazamiento es simple:
pageNumber(we see in the URL on the UI) -1 * limit

Donde pageNumber comienza en 1.

Paginación en acción 

  • También podemos aumentar el límite hasta 50 registros. No podemos aumentar el límite más de 50 registros ya que lo hemos especificado como el límite máximo en la función de middleware. El límite se ha establecido en el archivo server.js.
app.use(paginate.middleware(10, 50));

Lanzar una consulta como esta: http://localhost:8000/?page=1&limit=500 no causará un error, pero la cantidad de registros mostrados seguirá siendo 50. También podemos mejorar la funcionalidad para mostrar algunos mensajes que solo Se pueden ver 50 registros a la vez.

Interfaz de usuario que muestra solo 50 registros

Resumen: este artículo mostró cómo funciona la paginación con Node.js y MySQL usando una base de datos de muestra de MySQL. También vimos cómo podíamos limitar al usuario para que viera solo una cantidad determinada de registros en la página para no causar interrupciones en la interfaz de usuario. El código completo está disponible en el enlace de Github .

Publicación traducida automáticamente

Artículo escrito por reshmasathe y traducido por Barcelona Geeks. The original can be accessed here. Licence: CCBY-SA

Deja una respuesta

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *