Operaciones CRUD y carga de archivos usando Node.js y MongoDB

Dentro del mundo de la programación informática, CRUD es una elisión para las 4 operaciones Crear, Leer, Actualizar y Eliminar. Crear, leer, actualizar y eliminar (CRUD) son las cuatro funciones básicas que los modelos deberían poder hacer, como máximo. En las aplicaciones RESTful, CRUD a menudo corresponde a los métodos HTTP como POST, PUT, DELETE y GET respectivamente. Cada base de datos requiere que se llamen algunas funciones para que los usuarios puedan realizar algunas operaciones. Estas operaciones son utilizadas por los usuarios para realizar ciertos tipos de consultas sobre datos particulares dentro de la base de datos. La base de la operación son las operaciones CRUD. Las operaciones CRUD y la carga de archivos se realizarán con la ayuda del marco Node js y sus paquetes junto con MongoDB y Postman.

Operaciones CRUD

Antes de profundizar en cómo funciona el código, háganos saber los requisitos previos de las aplicaciones. La máquina local debe tener Node js, Postman y MongoDB instalados como requisitos previos. 

  • Node js (npm): si uno no tiene la instalación de Node.js y npm, vaya al enlace oficial para instalar Node.js y ejecute el siguiente comando en la terminal para descargar npm.
npm install npm@latest -g
  • Cartero: El cartero se utiliza para gestionar las requests. Ayuda a probar las requests HTTP, con la ayuda de la GUI sin copiar y pegar cada solicitud HTTP en todas partes. Vaya al enlace oficial para descargar PostMan gratis.
  • MongoDB: MongoDB es la base de datos que se utiliza en las operaciones CRUD. Si no tiene una cuenta MongoDB, no se preocupe, el artículo también le dará instrucciones paso a paso.

Se requiere que este proyecto se construya en el Node js con MongoDB como backend. Proporciona la siguiente capacidad a través de la interfaz API:

  • Carga de archivo CSV desde un formulario de varias partes
  • Escanee el CSV cargado e inserte su contenido en la colección MongoDB
  • API para realizar operaciones CRUD en la colección anterior

La API anterior está utilizando un paquete de pasaporte para la autenticación básica para administrar el acceso

Marco y entorno de tiempo de ejecución utilizados: Estos son los principales marcos y entornos de tiempo de ejecución que se utilizan en el proyecto.

  • Node js
  • Administrador de paquetes NPM
  • base de datos mongo
  • Cartero

Paso 1: Haz el proyecto Node.js. Para hacer eso, escriba el siguiente comando en la terminal.

npm init

Después de escribir el código en la terminal, debe completar la información. Para hacerlo predeterminado, presione ENTER en cada sección. Al final, obtendrá un archivo llamado package.json en su directorio. 

paquete.json

Algunos de los paquetes como dependencias se utilizan en este proyecto, a saber: express, express-session, bcryptjs, fast-csv, csvtojson, dotenv, multer, pasaporte, pasaporte-local y mongoose. Ejecute el comando para instalar estos paquetes.

 

Paso 2: Configure un servidor. Para configurar el servidor para la aplicación, cree 2 archivos llamados app.js y .env . app.js actuará como el archivo del servidor y .env ayudará a cargar las variables de entorno. 

Dentro del archivo .env, escriba el número de puerto para su host local PORT = «Número de puerto»  y en app.js escriba el siguiente código para ejecutar el servidor .

Javascript

const express = require('express');
const app = express();
const dotenv = require('dotenv');
 
dotenv.config();
 
app.use(express.json({limit: '20mb'}))
app.use(express.urlencoded({ extended: false, limit: '20mb' }))
 
/* Setting up server */
app.listen(process.env.PORT, function(){
    console.log("This server port is up and running ");
})

Para acceder a la carpeta de rutas donde se dan todas las requests, escriba la siguiente línea: 

Javascript

/* Initializing the path for routes */
app.use("/", require("./routes"));

El código final por ahora en app.js se verá así: 

Javascript

const express = require('express');
const app = express();
const dotenv = require('dotenv');
 
dotenv.config();
 
app.use(express.json({limit: '20mb'}))
app.use(express.urlencoded({ extended: false, limit: '20mb' }))
 
/* Initializing the path for routes */
app.use("/", require("./routes"));
 
/* Setting up server */
app.listen(process.env.PORT, function(){
    console.log("This server port is up and running ");
})

Paso para ejecutar la aplicación: Abra la terminal y escribiendo node app.js iniciará el servidor.

Servidor mirando al puerto número 3000

Paso 3: Conéctese a la colección MongoDB. Si uno no sabe cómo conectarse a MongoDB, siga los siguientes pasos; de lo contrario, omita los siguientes pasos: 

  1.  Ir a MongoDB Atlas
  2.  configurar una cuenta
  3.  Construir un nuevo proyecto 
  4.  Cree una base de datos (puede tardar un par de minutos)
  5.  Vaya al acceso a la base de datos y complete la sección de nombre de usuario, contraseña y dirección IP (puede cinco su dirección IP actual como predeterminada)
  6.  Haga clic en conectar y elija conectar su aplicación y le dará una dirección. Copie la dirección y péguela dentro del archivo .env

Construyendo un nuevo proyecto en MongoDB

El archivo .env final se verá así: 

DB_CONNECT = "YOUR PATH"
PORT = "Port Number"

Después de hacer una colección , conecte la aplicación Node.js con MongoDB escribiendo el siguiente código en app.js.

Javascript

global.dbconn = "";
 
/* Connected the app with mongoose */
mongoose.connect(
    process.env.DB_CONNECT,
    { useNewUrlParser: true, useUnifiedTopology: true },
    (client, err) =>{
        try{
            console.log("Connected to db: " + client)
        }catch(err){
            console.log(err);
        }
    }
);

Paso 4: Este paso describe la estructura de flujo del proyecto. El proyecto se divide en varias secciones. Hay una carpeta de middleware junto con el controlador , las rutas y la configuración . En la carpeta _others_  hay un archivo CSV ficticio para cargar. Al usar las rutas y cargarlas, el archivo CSV se carga en la carpeta de carga . Haga los siguientes archivos en cada sección.

NOTA: csv_controller.js y csv.js son solo programas para operaciones CRUD.

NOTA: No es necesario hacer csv copy.js, ya que es solo una copia de csv.js.

Estructura del proyecto

Esquema: En pocas palabras, el esquema es una estructura básica de toda la base de datos. Nos permite definir varios campos para que los usuarios ingresen.

Paso 5: Cree un esquema para el usuario y para la operación básica. Dado que los datos deben ser dinámicos, definiremos el esquema para la base de datos.

Bajo modelos: User.js

Javascript

const mongoose = require('mongoose');
 
/* Creating the schema with name, name, password and date */
const UserSchema = new mongoose.Schema({
    name: {
      type: String,
      required: true
    },
    email: {
      type: String,
      required: true
    },
    password: {
      type: String,
      required: true
    },
    date: {
      type: Date,
      default: Date.now
    }
  });
   
  /* Exporting schema with collection as CrudOperations */
  const User = mongoose.model('User', UserSchema);
   
  module.exports = User;

Se crea un esquema con el nombre Usuario que acepta nombre, correo electrónico, contraseña y fecha como sus campos.

crud.js

Javascript

const mongoose = require('mongoose');
 
/**
 * Creating the schema with username, identifier,
   firstName, lastName and updated
 */
const crud = new mongoose.Schema({
    username:{
        type: String,
        required: true,
    },
    identifier: {
        type: Number,
        required: true,
    },
    firstName:{
        type:String,
        required: true,
    },
    lastName:{
        type:String,
        required: true,
    },
    updated: {
        type: Date,
        required:true,
        default: Date.now,
    }
});
 
/**
 * Exporting schema with collection as CrudOperations
 */
module.exports = mongoose.model('CrudOperations', crud);

Dentro de crud.js se crea un esquema con los campos de aceptación nombre de usuario, identificador, nombre, apellido, actualizado.

Paso 6: Tener una autenticación y autorización adecuadas es muy importante en todas las organizaciones. Para eso cada organización pone una capa de seguridad. Los archivos auth.js y pasaporte.js están haciendo exactamente eso. Pero dado que el artículo ayuda a realizar operaciones CRUD y cargar archivos, no profundizaremos en él. 

NOMBRE DE ARCHIVO: auth.js

Javascript

module.exports = {
    /**
     * Ensuring authentication
     */
    ensureAuthenticated: function(req, res, next) {
      if (req.isAuthenticated()) {
        return next();
      }
      req.flash('error_msg', 'Please log in to view that resource');
      res.redirect('/users/login');
    },
    forwardAuthenticated: function(req, res, next) {
      if (!req.isAuthenticated()) {
        return next();
      }
      res.redirect('/dashboard');     
    }
  };

El archivo auth.js ve si el usuario ha iniciado sesión en la cuenta. En caso afirmativo, el usuario está autorizado a ver la página; de lo contrario, se le redirige a la página de inicio

NOMBRE DE ARCHIVO: pasaporte.js

Javascript

const LocalStrategy = require('passport-local').Strategy;
const bcrypt = require('bcryptjs');
 
// Load User model
const User = require('../models/User');
 
module.exports = function(passport) {
  passport.use(
    new LocalStrategy({ usernameField: 'email' }, (email, password, done) => {
      // Match user
      User.findOne({
        email: email
      }).then(user => {
        if (!user) {
          return done(null, false, { message: 'That email is not registered' });
        }
 
        // Match password
        bcrypt.compare(password, user.password, (err, isMatch) => {
          if (err) throw err;
          if (isMatch) {
            return done(null, user);
          } else {
            return done(null, false, { message: 'Password incorrect' });
          }
        });
      });
    })
  );
 
  passport.serializeUser(function(user, done) {
    done(null, user.id);
  });
 
  passport.deserializeUser(function(id, done) {
    User.findById(id, function(err, user) {
      done(err, user);
    });
  });
};

Junto con estos 2 archivos, se necesita una variable de sesión y una autorización para incluir el pasaporte en este proyecto. Para hacerlo, se abre app.js y se inicializa el middleware de pasaporte y la sesión.

NOMBRE DE ARCHIVO: app.js

Javascript

// Passport Config
require('./config/passport')(passport);
 
app.use(express.json({limit: '20mb'}))
app.use(express.urlencoded({ extended: false, limit: '20mb' }))
 
// Express session
app.use(
    session({
      secret: 'secret',
      resave: true,
      saveUninitialized: true
    })
);
   
  // Passport middleware
  app.use(passport.initialize());
  app.use(passport.session());

Paso 7: Se crea un middleware con la ayuda del paquete multer. Para usar el paquete multer, escriba el siguiente comando en la terminal.

npm install --save multer

El multer de paquetes ayuda en el manejo de datos de formularios/multipartes, que se utilizan principalmente para cargar archivos. Multer agrega un objeto de cuerpo y un objeto de archivo o archivos al objeto de solicitud. El objeto de cuerpo contiene los valores de los campos de texto del formulario, el objeto de archivo o archivos contiene los archivos cargados a través del formulario.

NOMBRE DE ARCHIVO: uploader.js

Javascript

const path = require('path')
const multer = require('multer')
 
var storage = multer.diskStorage({
    destination: function(req, file, cb){
        cb(null, 'uploads/')
    },
    filename: function(req, file, cb){
        let ext = path.extname(file.originalname)
        cb(null, Date.now() + ext);
    }
})
 
var upload = multer({
    storage: storage,
    fileFilter: function(req, file, callback){
        if(
            file.minetype == "text/csv"
        ){
            callback(null, true)
        } else{
            console.log("Error in uploading")
            callback(null, false)
        }
    },
    limits: {
        fileSize: 1024 * 1024 * 2
    }
})
 
module.exports = upload

Paso 8:  Después de realizar la autenticación con Passport y Multer a medida que se agrega el middleware al proyecto, es necesario completar las rutas y el controlador para la carga de archivos y las operaciones CRUD.

Antes de saltar a las operaciones, primero es necesario inicializar las rutas. Para ello se utiliza index.js .

NOMBRE DE ARCHIVO: index.js

Javascript

const express = require("express");
var router = express.Router();
 
/* Initializing other routes */
router.use("/", require("./csv"));
router.use('/', require('./users.js'));
 
module.exports = router;

Para usar la autenticación de pasaporte, las rutas y el controlador para el usuario se realizan en users.js y user_controller.js.

NOMBRE DE ARCHIVO: usuarios.js

Javascript

const express = require('express');
const router = express.Router();
const userController = require("../controller/user_controller")
/* Register router with passport package */
router.post('/register', userController.register);
   
/* Login router */
router.post('/login', userController.login);
 
/* Logout router  */
router.get('/logout', userController.logout);
 
module.exports = router;

Hace la ruta para el registro y el inicio de sesión como método de publicación y un sistema de cierre de sesión como método de obtención. Dentro del controlador_usuario.

NOMBRE DE ARCHIVO: controlador_usuario.js

Javascript

const express = require('express');
const router = express.Router();
const bcrypt = require('bcryptjs');
const passport = require('passport');
// Load User model
const User = require('../models/User');
const { forwardAuthenticated } = require('../config/auth');
 
exports.register = (req, res) => {
    console.log("Request: " + JSON.stringify(req.body))
    const { name, email, password, password2 } = req.body;
    let errors = [];
   
    /* If condition to check whether all credentials are filled */
    if (!name || !email || !password || !password2) {
      errors.push({ msg: 'Please enter all fields' });
    }
     
    /* If condition to check whether password
    and password2 matches or not */
    if (password != password2) {
      errors.push({ msg: 'Passwords do not match' });
    }
   
    /* If condition to check in case password
    length is greater than 3 or not */
    if (password.length < 3) {
      errors.push({ msg: 'Password must be at least 3 characters' });
    }
   
    if (errors.length > 0) {
      res.send('register error')
    } else {
     
    /* Checking if user exsists */
      User.findOne({ email: email }).then(user => {
        if (user) {
          errors.push({ msg: 'Email already exists' });
          res.send('register user exsists');
        }
         
       /* Creating the user */
       else {
          const newUser = new User({
            name,
            email,
            password
          });
           
          /* Brcypt hashing the password for user privacy */
          bcrypt.genSalt(10, (err, salt) => {
            bcrypt.hash(newUser.password, salt, (err, hash) => {
              if (err) throw err;
              newUser.password = hash;
              newUser
                .save()
                .then(user => {
                  res.send("Register Successful");
                })
                .catch(err => console.log(err));
            });
          });
        }
      });
    }
  }
 
exports.login = (req, res, next) => {
 
    /* Authenticating if login was successful or
    not with the help of passport */
passport.authenticate('local', {
    successRedirect: res.send("Login Successful"),
    failureRedirect: res.send("Error in Login"),
    failureFlash: false
})(req, res, next);
}
 
exports.logout = (req, res) => {
    req.logout();
   /* Logging out */
    res.send("User Logout");
}

El exportador registrado primero verifica si las credenciales dadas son correctas o no. Si son correctos, la contraseña se cifra con la ayuda de brcypt. Y después de eso, se guarda un nuevo usuario dentro del esquema. Para verificar si la función funciona o no, se envía una solicitud con la ayuda del cartero para registrarse, iniciar sesión y cerrar sesión.

Registrarse: enviar una solicitud de publicación http://localhost:3000/register con la ayuda del cartero.

Solicitud de registro del cartero

Después de que el registro sea exitoso, se puede ver al mismo usuario en el atlas de MongoDB.

Usuario en MongoDB

Iniciar sesión: enviar una solicitud de publicación http://localhost:3000/login

 

Cerrar sesión: cerrar sesión envía una solicitud de obtención .

 

Operaciones Crud y carga de archivos: utilizando los archivos csv.js y csv_controller.js, se realizarán todas las operaciones CRUD y la carga de archivos. Se llaman varias API que ayudan a lograr varias funciones. Al igual que http://localhost:3000/fileUpload, ayuda a cargar el archivo CSV y enviar los datos a Mongoose. Del mismo modo, http://localhost:3000/CRUDcreate, http://localhost:3000/CRUDread, http://localhost:3000/CRUDupdate, http://localhost:3000/CRUDdelete ayuda en otras operaciones CRUD CREATE, READ, ACTUALIZAR y ELIMINAR respectivamente.

Crear: enviaremos la solicitud de publicación . Como su nombre lo indica, crean funciones para que todos los usuarios ingresen un nuevo registro en la base de datos. Para una base de datos relacional, se llama a una función de creación conocida como INSERTAR. En bases de datos no relacionales como MongoDB ofrece dos opciones diferentes para insertar documentos en la colección: db.collection.insertOne()
db.collection.insertMany(). 

NOMBRE DE ARCHIVO: csv.js

Javascript

/* Creating a schema for crud operation C: Create */
router.post("/CRUDcreate",  forwardAuthenticated, csvController.create)

NOMBRE DE ARCHIVO: csv_controller.js

Javascript

exports.create = async function(req, res){
    /* Initializing the schema and putting in CRUDcreate */
    const CRUDcreate = new CRUDoperations ({
        username: req.body.username,
        identifier:req.body.identifier,
        firstName: req.body.firstName,
        lastName: req.body.lastName
    });
 
    /* Try Catch */
    try{
        /* Saving the data in mongoose */
        const savedCRUD = await CRUDcreate.save();
        /* Sending the response back */
        res.status(200);
        res.send(savedCRUD);
    }catch(err){
        /* Sending the error back */
        res.status(400).send(err);
    }  
}

Una vez realizada la operación después de agregar los paquetes necesarios en los archivos, se utiliza .save() para guardar la información en la base de datos.

CRUD (Crear)

Leer: La función de lectura en la operación CRUD es similar a una función de búsqueda. Lo que hace ayuda al usuario a buscar y recuperar información particular de un dato en particular. En MongoDB usamos db.collection.find() o db.collection.findOne() para recuperar la información.

NOMBRE DE ARCHIVO: csv.js

Javascript

/* Router for CRUD operation R: read */
router.get("/CRUDread", csvController.read)

NOMBRE DE ARCHIVO: csv_controller.js

Javascript

exports.read = function(req, res){
    /* Using find() for reading all the data */
    CRUDoperations.find({}, function(err, fetch){
        /* In case of error */
        if(err) res.status(400).send(err);
 
        /* Sending back the response */
        res.status(200).send(fetch);       
    });
}

CRUD (Leer)

Actualizar: La función de actualización se utiliza para modificar los datos presentes en la colección de la base de datos MongoDB. PARA cambiar un registro, es posible que los usuarios tengan que modificar varios campos. Esto requiere una cuidadosa actualización de los documentos, ya que los cambios realizados durante la actualización de la colección son permanentes e irreversibles. Se pueden usar 3 métodos diferentes en MongoDB para actualizar: db.collection.updateOne(), db.collection.updateMany(), db.collection.replaceOne().

NOMBRE DE ARCHIVO: csv.js

Javascript

/* CRUD operation 'update' router */
router.post("/CRUDupdate", csvController.update)

NOMBRE DE ARCHIVO: csv_controller.js
 

Javascript

exports.update = async function(req, res){
    /* Taking the id */
    let id = req.body._id;
 
    try{
        /* Using findByIdAndUpdate */
        const CRUDupdate = await CRUDoperations.findByIdAndUpdate({_id: id},
         
        /* Setting the value of identifier as 1967 of corresponding id */
        {$set:{
                identifier: 1969
              }
        },
        {
            useFindAndModify: false
        });
 
        /* Sending the response back to the server */
        res.status(200).send(CRUDupdate);
    }catch(err){
        /* Sending error back to the server */
        res.status(400).send(err);
    }
}

CRUD (Actualización)

Eliminar: la última operación CRUD es Eliminar. Como su nombre indica, ayuda a eliminar una sola colección de un documento.

db.colección.deleteOne()
db.colección.deleteMany()

NOMBRE DE ARCHIVO: csv.js

Javascript

/* Router to perform delete of CRUD operations */
router.post("/CRUDdelete", csvController.delete)

NOMBRE DE ARCHIVO: csv_controller.js

Javascript

exports.delete =  async function(req, res){
    /* Taking the id of the collection */
    let id = req.body._id;
 
    /* Using Try and catch for deletion */
    try{
        /* Using findbyIdAndRemove operation to remove
        the data with corresponding id */
        const CRUDdel = await CRUDoperations.findByIdAndRemove(
        id, function(err, res){
            if (err){
                /* Sending error back to the server */
                res.status(400).send(err);
                console.log(err)
            }
            else{
                 
                /* Sending the response back to the server */
                console.log("Removed User : ", res);
            }
        },
        {
            useFindAndModify: false
        })
    }catch(err){
        res.status(400).send(err);
    }
}

CRUD (Borrar)

Carga de archivos: como se discutió antes, la carga de archivos se realiza con la ayuda del paquete multer.

NOMBRE DE ARCHIVO: csv.js

Javascript

const fileStorageEngine = multer.diskStorage({
    destination: (req, file, cb) => {
        cb(null, './uploads')
    },
    filename: (req, file, cb) => {
        cb(null, Date.now() + "--" + file.originalname);
    },
});
 
const upload = multer({ storage: fileStorageEngine });
 
router.post('/single', upload.single('fileUpload'), (req, res) => {
    console.log('single route')
    console.log('file:'+JSON.stringify(req.file));
    res.send("single file upload success");
});
 
 
router.post("/fileUpload",upload.single('fileCSV'),
    csvController.fileupload)

NOMBRE DE ARCHIVO: csv_controller.js

Javascript

exports.fileupload = function(req, res){
    console.log("Inside file Upload!!")
    console.log('single route')
    console.log('file:'+JSON.stringify(req.file.path));
 
 
    let stream = fs.createReadStream(req.file.path)    
         
    let csvData = [];
 
    let csvStream = fastcsv
        .parse()
        .on('error', error => console.error(error))
        .on("data", function(data) {
            //console.log("Data Parse: " + JSON.stringify(data))
            dt = data[0].split(',')
            //console.log("DT: " + dt[0])
            csvData.push({
                username: dt[0],
                identifier: dt[1],
                firstName: dt[2],
                lastName: dt[3]
            });
            //console.log((csvData));
        })
        .on("end", async function() {
            // remove the first line: header
            csvData.shift();
 
            // save to the MongoDB database collection
            try{
                console.log("client:" + CRUDoperations);
                let CRUDinsert = await CRUDoperations.insertMany(
                    csvData
                )
                console.log("CRUD Insert Many" + CRUDinsert)
                res.status(200).send(CRUDinsert);
 
            } catch(err){
                console.log("db error:"+err);
                res.status(400).send(err);
            }
            console.log(JSON.stringify(csvData));
        });
 
    stream.pipe(csvStream);
}

Carga de archivos: entrada

 

Publicación traducida automáticamente

Artículo escrito por arnavmahajan01 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 *