A煤n no tienes acceso a esta clase

Crea una cuenta y contin煤a viendo este curso

Tu primer modelo en Sequelize

10/27
Recursos

Aportes 24

Preguntas 11

Ordenar por:

驴Quieres ver m谩s aportes, preguntas y respuestas de la comunidad? Crea una cuenta o inicia sesi贸n.

Aclaraciones de la documentaci贸n

馃敟Nuestra documentaci贸n nos permite aclarar unos detalles que quedaron volando:

  • Podemos utilizar define o extend Model.
  • Se infiere el nombre de la tabla y se generaliza en plural, sequelize.define('user', userSchema); definir谩 la tabla users.
  • Existe el modo de sincronizaci贸n global sequelize.sync() o particular modelo.sync()` donde tendremos par谩metros:
    • force: true. Eliminar la existencia previa y creando en secuencia.
    • alter: true. Revisa si se cambiar谩 alguna estructura, la nueva vs la previa.

.

Configuraci贸n de ORM

鈩癸笍Repositorio: link
.
鈾伙笍Reutilizando las variables de entorno, las organizamos para determinar aquellas para database.

config.js . Archivo de definici贸n de variables de entorno

/**
 * @description variables of database server
 */
export const database = {
    dbName: process.env.PGDATABASE,
    dbHost: process.env.PGHOST || 'localhost',
    dbPort: process.env.PGPORT || '5432',
    dbUser: process.env.PGUSER,
    dbPassword: process.env.PGPASSWORD,
};

.
鈾伙笍Definimos la librer铆a de sequelize mediante la abstracci贸n OOP.

Sequelize.js . Archivo de definici贸n de variables de entorno

import { Sequelize as SequelizeClient } from 'sequelize';
import { database } from '../config/config';
import Error from '../utils/Error';

const USER = encodeURIComponent(database.dbUser);
const PASSWORD = encodeURIComponent(database.dbPassword);
const URI = `postgres://${USER}:${PASSWORD}@${database.dbHost}:${database.dbPort}/${database.dbName}`;

export default class Sequelize {
    /**
     * @private
     * @description singleton pattern for pool connection
     * @returns {object} - connection client
     */
    async #connect() {
        try {
            if (!Sequelize.connection) {
                Sequelize.connection = new SequelizeClient(URI, {
                    logging: false,
                });
                await Sequelize.connection.authenticate();
            }
            return Sequelize.connection;
        } catch ({ message }) {
            throw new Error(message, 'DRIVER');
        }
    }
    /**
     * @description process definition for create database tables
     * @param {string} name - table name
     * @param {string} schema - table description
     * @returns {Promise} - response of library
     */
    async define(name, schema) {
        try {
            const db = await this.#connect();
            const model = await db.define(name, schema);
            return await model.sync();
        } catch (error) {
            if (!error) throw new Error(message, 'DEFINITION');
            throw error;
        }
    }
}

.
鉁–reamos el schema

user.js

import { DataTypes, Sequelize as SequelizeClient } from 'sequelize';

/**
 * @description description of each field in the table
 * @typedef {Object} field definition
 * @property {boolean} allowNull - false=NOT NULL
 * @property {boolean} autoIncrement - each insert, increase the counter
 * @property {boolean} primaryKey - define is primary key
 * @property {boolean} type - expresion to match SQL type
 * @property {boolean} unique - difne as unique the field
 * @property {boolean} field - rename the field
 */
export default {
    id: {
        allowNull: false,
        autoIncrement: true,
        primaryKey: true,
        type: DataTypes.INTEGER,
    },
    email: {
        allowNull: false,
        type: DataTypes.STRING,
        unique: true,
    },
    password: {
        allowNull: false,
        type: DataTypes.STRING,
    },
    createdAt: {
        allowNull: false,
        type: DataTypes.DATE,
        field: 'created_at',
        defaultValue: SequelizeClient.DATE,
    },
    updatedAt: {
        allowNull: false,
        type: DataTypes.DATE,
        field: 'updated_at',
        defaultValue: SequelizeClient.DATE,
    },
};

.
鉁–reamos nuestro seed

seed.js . Archivo de creaci贸n de entorno limpio npm run seed

import Sequelize from './../libs/sequelize';
import userSchema from './models/user';
import { complete, fail } from '../utils/Log';

const sequelize = new Sequelize();
const user = sequelize.define('user', userSchema);

Promise.all([user])
    .then((responses) => complete('Creation process', responses))
    .catch(({ message }) => fail('Creation process', message));

Wow sinceramente esta clase la senti pesada, es la configuraci贸n m谩s compleja de base de datos/ORM que haya realizado, comparado con Java Spring, Nest JS, Node con Mongo, Laravel鈥

Esta clase fue genial, no sab铆a que se pod铆a persistir datos con un esquema de una manera tan f谩cil.
Adicional me gustar铆a compartir la diferencia entre un m茅todo static y uno no static.

Cuando se crea un m茅todo no est谩tico en una clase. primero se tiene que crear un objeto (instancia) de la clase.
Ej.

class Users {
	metodoNoEstatico() {
		//  Una l贸gica loca...
	}
}

// Para hacer uso del m茅todo no est谩tico se crea un objeto de la clase.
const user = new Users();
user.metodoNoEstatico();

Cuando el m茅todo es static no se requiere crear un objeto de la clase. Ej.

class Users {
	static metodoEstatico() {
		//  Una l贸gica loca...
	}
}

// Para hacer uso del m茅todo est谩tico no se necesita crear un objeto.
Users.metodoEstatico();

Esto es porque los m茅todos static se cargan en memoria sin la necesidad de cargar/crear el objeto de la clase.

Si necesitas un poco de ayuda visual para entender como se van haciendo las relaciones en la base de datos te comparto la siguiente imagen.

CamelCase
snake_case

En .Net es 100 veces m谩s sencillo.

Estos temas estan muy muy interesantes, estas librerias para las BD estan buenisimas.

Si hemos puesto primary key en el UserSchema no ser铆a redundante poner allowNull: false?

En este curso, b谩sicamente yo seleccione como Base de datos Mysql, en vista que no pude configurar dockers con la imagen de Postgress, al final casi que son hermanas estas BD, pero he podido avanzar tal cual lo que el profesor indica. Esto demuestra que no importa la BD que uses (Tipo SQL) con un ORM o Pool, es la misma configuraci贸n para distintas BD. 馃懡

S铆ganme por instagram como: mrandycode y twitter mrandycode

Si alguien desea ver una configuraci贸n r谩pida de Sequelize pueden revisar este repositorio, exactamente en la carpeta server.
Repo: https://github.com/omar11011/serena_bot_discord

Dato:
Supongo es bastante intuitivo, pero si se preguntan, 驴Por que en createdAt utilizamos field y en las otras no?

Por defecto el nombre de la columna tendra el nombre de la llave, en el caso de createdAt, debiamos cambiar la convenci贸n de camelCase a snake_case, por lo mismo renombramos la columna con el atributo field

Mediante el CLI de sequelize podemos generar todo m谩s r谩pido y f谩cil.

  1. Instalas el cli como dependencia de desarrollo
    npm i -S sequelize-cli.
  2. Crea un archivo con el nombre .sequelizerc a la altura de tu package.json.
  3. Ingresa a este link Sequelize cli y busca la secci贸n donde definen su contenido.
  4. Copia ese contenido, que en resumen crea las rutas de tu config, models, migratios y seeders. Esta es la config que yo us茅:
// path ./.sequelizerc
const path = require('path');

module.exports = {
  'config': path.resolve('database', 'config.js'),
  'models-path': path.resolve('database', 'models'),
  'seeders-path': path.resolve('database', 'seeders'),
  'migrations-path': path.resolve('database', 'migrations')
};
  1. Como puedes ver, por defecto el archivo config es un json, aqu铆 est谩 la original, pero yo lo cambi茅 por un .js como lo hace m谩s adelante el profesor. Aqu铆 te dejo el c贸digo.
// path ./database/config.js
require('dotenv/config')

const { DB_PORT, DB_HOST, DB_NAME, DB_PASS, DB_USER } = process.env

module.exports = {
  development: {
    username: DB_USER || "postgres",
    password: DB_PASS || "admin",
    database: DB_NAME || "littleStore",
    dialect: "postgres",
    host: DB_HOST || "127.0.0.1",
    port: DB_PORT || 5432,
    logging: false
  }
}
  1. Corre el comando npx sequelize-cli init, y te crear谩 todas las carpetas que necesitas, excepto por el config.js que ya lo tienes.
  2. Edita y crea tus modelos, migraciones y seeds mediante la gu铆a porque el profesor en esta clase lo hace a mano. Es cierto que necesitas saber que son los seeds para poder usarlos, pero no hay mejor manera de aprender que hechandolo a perder. O siguiendo una gu铆a de youtube o aqu铆.

Estuvo potente la clase

El shema (Esquema)
Se refiere a la estructura de las tablas(Nombres y tipos de campo etc.)
Creamos una carpeta para guardar todo lo relacionado a la base de datos y se llama db, dentro ponemos la carpeta models y detro creamos un modelo llamado user.model.js , recuerda que es un modelo por tabla, en este archivo se importa sequelize y se traen 3 elementos: Model, DataTypes y Sequelize este archivo lleva 5 elementos importantes

  1. Se importa sequelize
  2. Se declara una constante que tendr谩 el nombre de la tabla
  3. Se declara el esquema (UserShema)
  4. Se extiende la clase Model en una nueva clase llamada como el modelo
  5. Por ultimo se exportan los elementos 2,3 y 4

Se empieza a trabajar con esquemas de bases de datos para aprovechar las ventajas del ORM.

Dentro de la carpeta db habr谩 una carpeta models donde se guardar谩n los modelos de la BD.

Una buena practica para el naming en Sequelize y en las bases de datos es NO usar camelCase, m谩s bien, usar snake_case. Cabe mencionar que en las variables de JavaScript s铆 es posible (ver ejemplo):

createdAt: { // Variable JavaScript
    allowNull: false,
    type: DataTypes.DATE,
    field: 'created_at', // Naming en Sequelize
    defaultValue: Sequelize.NOW // Valor por defecto (c贸mo se registr贸 en Sequelize)
  }

Se puede definir una clase del modelo y extenderlo de Model el cual contiene todas las formas de hacer queries. Ejemplo class User extends Model.

Un m茅todo est谩tico significa que no necesito una declaraci贸n (no se necesita declarar el objeto) para acceder a esos m茅todos. Va a funcionar para definir las asociaciones.

Se define otro m茅todo est谩tico para la configuraci贸n, recibe una conexi贸n que usualmente se llama sequelize y se retorna una configuraci贸n con la conexi贸n, el nombre de la tabla, el nombre del modelo y el timestamps (por default).

user.model.js:

const { Model, DataTypes, Sequelize } = require('sequelize');
const USER_TABLE = 'users'; // nombre de la tabla

const UserSchema = {
  // El esquema define la estructura de la BD.
  id: {
    allowNull: false,
    autoIncrement: true,
    primaryKey: true,
    type: DataTypes.INTEGER,
  },
  email: {
    allowNull: false,
    type: DataTypes.STRING,
    unique: true,
  },
  password: {
    allowNull: false,
    type: DataTypes.STRING,
  },
  createdAt: {
    allowNull: false,
    type: DataTypes.DATE,
    field: 'created_at',
    defaultValue: Sequelize.NOW,
  },
};

class User extends Model {
  static associate() {
    // models
  }

  static config(sequelize) {
    return {
      sequelize,
      tableName: USER_TABLE,
      modelName: 'User',
      timestamps: false,
    };
  }
}

module.exports = { USER_TABLE, UserSchema, User };

Dentro de la carpeta db/models se crea un archivo index.js el cual se va a encargar de enviar la conexi贸n hacia los modelos, y con esto podr谩 hacer todo el mapeo y serializaci贸n de datos. Ah铆 se incluyen todos los modelos.

La funci贸n setupModels tendr谩 la configuraci贸n de los modelos, recibe la conexi贸n como par谩metro. Ah铆 se incluye todo el setup inicial de los modelos.

Al .init() se le env铆a el schema, posteriormente la configuraci贸n con el m茅todo est谩tico. Ejemplo: User.init(UserSchema, User.config(sequelize));

index.js:

const { User, UserSchema } = require('./user.model');

function setupModels(sequelize) {
  User.init(UserSchema, User.config(sequelize));
}

module.exports = setupModels;

En el archivo sequelize.js se corre la funci贸n setupModels, dentro del archivo se require la funci贸n, se inicializa pas谩ndole la conexi贸n y se hace una sincronizaci贸n, es decir, leer los modelos y crear una estructura incluyendo las tablas.

sequelize.js:

const { Sequelize } = require('sequelize');

const { config } = require('../config/config');
const setupModels = require('../db/models/');

const USER = encodeURIComponent(config.dbUser);
const PASSWORD = encodeURIComponent(config.dbPassword);
const URI = `postgres://${USER}:${PASSWORD}@${config.dbHost}:${config.dbPort}/${config.dbName}`;

const sequelize = new Sequelize(URI, { dialect: 'postgres', logging: true }); // Se crea una instancia de Sequelize.

setupModels(sequelize);
sequelize.sync();

module.exports = sequelize;

Para hacer una consulta, en el archivo de servicios se require el archivo sequelize de la capa de librer铆as. Cada vez que en sequelize se le env铆a setupModels y se le da el .init(), se crea un namespace, un espacio reservado para guardar los modelos, o al menos la forma de acceder a ellos. El nombre del modelo ser谩 el asignado en modelName del archivo de un modelo especifico (ej. user.model.js).

El m茅todo para consultar todos los registros de una tabla es .findAll(). y se hace de la siguiente manera:

const { models } = require('../libs/sequelize');

async find() {
    const rta = await models.User.findAll();
    return rta;
  }

Me ha encantado! Muy similar a las migraciones de laravel.

Este curso anda con todo 馃槃

Excelente yo lo hice con Mssql y todo bien, con ello migrar bases se hace m谩s facil !

Para crear la tabla es mas f谩cil con Define, tenemos la conexi贸n en un archivo aparte:

import { Sequelize } from "sequelize";

const db = new Sequelize("platzi", "postgres", "postgres", {
  host: "localhost",
  dialect: "postgres",
  //logging:false
});

export default db;

y tenemos el modelo

import { DataTypes } from "sequelize";
import db from "../db/conection";

const Usuario = db.define("user",{
    id: {
      allowNull: false,
      autoIncrement: true,
      primaryKey: true,
      type: DataTypes.INTEGER,
    },
    email: {
      allowNull: false,
      unique: true,
      type: DataTypes.STRING,
    },
    password: {
      allowNull: false,
      type: DataTypes.STRING,
    },
    createAt: {
      allowNull: false,
      type: DataTypes.DATE,
      field: "create_at", // el verdadero nombre como quiero que se cree
      defaultValue: DataTypes.NOW,
    },
  },
  {
    timestamps: false, // Para que no se creen los timestamps: createdAt y updatedAt por default
  }
);

//Creamos la tabla
Usuario.sync();

export default Usuario;

Para hacer la consulta importamos el modelo :

import Usuario from "../models/usuario";

y consultamos:

import { Request, Response } from "express";
import Usuario from "../models/usuario";

export const getUsuarios = async (req: Request, res: Response) => {
  const usuarios = await Usuario.findAll();

  res.json({
    usuarios,
  });
};

y ya eso seria todo 馃槂

les dejo mi repo hasta le momento https://github.com/bdavidegonzalez/my-store yo utilice typescript tal vez alguno le sirva

A m铆 me cre贸 una columna extra llamada 鈥渦pdatedAt鈥 que yo ni la defin铆 en el UserSchema鈥 馃憖

鈥 Aliens? 馃懡馃憪

productModel.js

const { Model, DataTypes, Sequelize } = require('sequelize');

const PRODUCT_TABLE = 'products';

const ProductSchema = {
  id: {
    allowNull: false,
    autoIncrement: true,
    primaryKey: true,
    type: DataTypes.INTEGER
  },
  productName: {
    allowNull: false,
    type: DataTypes.STRING,
    field: 'product_name',
  },
  price: {
    allowNull: false,
    type: DataTypes.REAL
  },
  stockNumber: {
    allowNull: true,
    type: DataTypes.REAL,
    field: 'stock_number',
  },
  category: {
    allowNull: true,
    type: DataTypes.STRING,
  },
  createdAt: {
    allowNull: false,
    type: DataTypes.DATE,
    field: 'create_at',
    defaultValue: Sequelize.NOW
  }
}

class Product extends Model {
  static associate(){

  }

  static config(sequelize){
    return {
      sequelize,
      tableName: PRODUCT_TABLE,
      modelName: 'Product',
      timestamps: false,
    }
  }
}

module.exports = { PRODUCT_TABLE, ProductSchema, Product }

categoryModel.js

const { Model, DataTypes, Sequelize } = require('sequelize');

const CATEGORY_TABLE = 'categories';

const CategorySchema = {
  id: {
    allowNull: false,
    autoIncrement: true,
    primaryKey: true,
    type: DataTypes.INTEGER
  },
  category: {
    allowNull: false,
    type: DataTypes.STRING,
  },
  createdAt: {
    allowNull: false,
    type: DataTypes.DATE,
    field: 'create_at',
    defaultValue: Sequelize.NOW
  },
}

class Category extends Model {
  static associate(){

  }

  static config(sequelize){
    return {
      sequelize,
      tableName: CATEGORY_TABLE,
      modelName: 'Category',
      timestamps: false,
    }
  }
}

module.exports = { Category, CategorySchema, CATEGORY_TABLE }

db/model/index.js

const { User, UserSchema } = require ('./userModel');
const { Product, ProductSchema } = require ('./productModel');
const { Portfolio, PortfolioSchema} = require ('./portfolioModel');
const { Category, CategorySchema } = require ('./categoryModel')


function setupModels(sequelize) {
  User.init(UserSchema, User.config(sequelize));
  Product.init(ProductSchema, Product.config(sequelize));
  Portfolio.init(PortfolioSchema, Portfolio.config(sequelize));
  Category.init(CategorySchema, Category.config(sequelize));
}

module.exports = setupModels;

aparte de que esta clase si estuvo bastante pesada y avanzada, aprendi a irme a una funcion de otro archivo precionando ctrl click

Seg煤n entend铆 c贸mo funciona, en retrospectiva, el flujo de trabajo que est谩 ocurriendo es el siguiente:

  • La ruta o endpoint, llama al servicio. (users.router.js)
  • El servicio, genera la conexi贸n sequelize al modelo. (users.service.js)
  • Se llama a setupModels, enviando la conexi贸n. (sequelize.js)
  • Dentro de setupModels, se inicializa el modelo con init(), pasando el modelo y la configuraci贸n. (models/index.js)
  • El modelo, extiende los m茅todos de sequelize, tal como findAll() para realizar el query. (user.model.js)
  • Se retorna la respuesta obtenida de la DB.

Uff el ORM facilita mucho la ejecuci贸n de queries. En la pr谩ctica 驴Qu茅 es mejor, simplificarte el trabajo un poco usando ORM o usar el lenguaje que nos proporciona el DBMS? 驴Hay alg煤n est谩ndar que nos diga cuando utilizar cada uno?