No tienes acceso a esta clase

隆Contin煤a aprendiendo! 脷nete y comienza a potenciar tu carrera

Aprende todo un fin de semana sin pagar una suscripci贸n 馃敟

Aprende todo un fin de semana sin pagar una suscripci贸n 馃敟

Reg铆strate

Comienza en:

3D
23H
41M
23S

Consideraciones al hacer migraciones

26/27
Recursos

Aportes 19

Preguntas 13

Ordenar por:

驴Quieres ver m谩s aportes, preguntas y respuestas de la comunidad?

o inicia sesi贸n.

Me carga el payaso鈥 tengo m谩s de 20 migraciones porque me puse a jugar con las tablas y las columnas en clases anteriores. Me toc贸 hacer una faena 茅pica.

Mi archivo 煤nico de migraciones es algo como esto:

'use strict';
const { DataTypes, Sequelize } = require('sequelize');
const { USER_TABLE, UserSchema } = require('../models/userModel')
const { CUSTOMER_TABLE, CustomerSchema } = require('../models/customerModel')
const { CATEGORY_TABLE, CategorySchema } = require('../models/categoryModel')
const { PRODUCT_TABLE, ProductSchema } = require('../models/productModel')
const { ORDER_TABLE } = require('../models/orderModel')
const { OrderProductSchema, ORDER_PRODUCT_TABLE } = require('../models/order-productModel')


module.exports = {
  up: async (queryInterface) => {
    await queryInterface.createTable(USER_TABLE, UserSchema);
    await queryInterface.createTable(CUSTOMER_TABLE, CustomerSchema);
    await queryInterface.createTable(CATEGORY_TABLE, CategorySchema);
    await queryInterface.createTable(PRODUCT_TABLE, ProductSchema);
    await queryInterface.createTable(ORDER_TABLE, {
      id: {
        allowNull: false,
        autoIncrement: true,
        primaryKey: true,
        type: DataTypes.INTEGER
      },
      customerId: {
        field: 'customer_id',
        allowNull: false,
        type: DataTypes.INTEGER,
        references: {
          model: CUSTOMER_TABLE,
          key: 'id'
        },
        onUpdate: 'CASCADE',
        onDelete: 'SET NULL'
          },
      createdAt: {
        allowNull: false,
        type: DataTypes.DATE,
        field: 'created_at',
        defaultValue: Sequelize.NOW,
        },
    });
    await queryInterface.createTable(ORDER_PRODUCT_TABLE, OrderProductSchema);

  },

  down: async (queryInterface) => {
    await queryInterface.dropTable(USER_TABLE)
    await queryInterface.dropTable(CUSTOMER_TABLE)
    await queryInterface.dropTable(CATEGORY_TABLE)
    await queryInterface.dropTable(PRODUCT_TABLE)
    await queryInterface.dropTable(ORDER_TABLE)
    await queryInterface.dropTable(ORDER_PRODUCT_TABLE)
  }
};

Grande Nicol谩s! Te la comiste con este curso. Mil gracias, aprend铆 un mont贸n!

este curso est谩 10/10 鈽

En mi opini贸n (para este caso) es mucho m谩s sencillo borrar todas las migraciones y crear una sola en limpio con su respectivo c贸digo.

Con esto no habr铆a ning煤n inconveniente al subirlo a producci贸n. Claro, habr铆a otras complicaciones m谩s adelante en Development, pero si no tienen problema, pueden borrar y crear nuevamente las tablas de la base de datos.

Las migraciones son muy delicadas, es por ello que se deben tener en cuenta los esquemas. A nivel producci贸n no se recomienda crear migraciones paso a paso, m谩s bien, crear una sola migraci贸n que ya tenga todas las relaciones y configuraci贸n por defecto.

Una buena practica es no repetir el c贸digo, pero en este caso se va necesitar repetir el esquema cuando se creen las tablas.

Cada vez que agregamos un atributo o algo parecido, lo mejor es no basarse en el esquema porque es algo gen茅rico y no est谩 versionado, sirve para el modelo, pero no es buena practica que sea la base de las migraciones porque lo configuramos en cualquier momento y puede da帽ar la configuraci贸n.

Los archivos que se cambiaron fueron los siguientes:

Migraci贸n create-user.js:

'use strict';

const { USER_TABLE } = require('../models/user.model');
const { DataTypes, Sequelize } = require('sequelize');

module.exports = {
  up: async (queryInterface) => {
    await queryInterface.createTable(USER_TABLE, {
      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,
      },
    });
  },

  down: async (queryInterface) => {
    await queryInterface.dropTable(USER_TABLE);
  },
};

Migraci贸n add-role.js:

'use strict';

const { USER_TABLE } = require('../models/user.model');
const { DataTypes } = require('sequelize');

module.exports = {
  up: async (queryInterface) => {
    await queryInterface.addColumn(USER_TABLE, 'role', {
      allowNull: false,
      type: DataTypes.STRING,
      defaultValue: 'customer',
    });
  },

  down: async (queryInterface) => {
    await queryInterface.removeColumn(USER_TABLE, 'role');
  },
};

Migraci贸n create-customers.js:

'use strict';

const { CUSTOMER_TABLE } = require('../models/customer.model');
const { USER_TABLE } = require('../models/user.model');
const { DataTypes, Sequelize } = require('sequelize');

module.exports = {
  up: async (queryInterface) => {
    await queryInterface.createTable(CUSTOMER_TABLE, {
      id: {
        allowNull: false,
        autoIncrement: true,
        primaryKey: true,
        type: DataTypes.INTEGER,
      },
      name: {
        allowNull: false,
        type: DataTypes.STRING,
      },
      lastName: {
        allowNull: false,
        type: DataTypes.STRING,
        field: 'last_name',
      },
      phone: {
        allowNull: false,
        type: DataTypes.STRING,
      },
      createdAt: {
        allowNull: false,
        type: DataTypes.DATE,
        field: 'created_at',
        defaultValue: Sequelize.NOW,
      },
      userId: {
        field: 'user_id',
        allowNull: false,
        type: DataTypes.INTEGER,
        references: {
          model: USER_TABLE,
          key: 'id',
        },
        onUpdate: 'CASCADE',
        onDelete: 'SET NULL',
      },
    });
  },

  down: async (queryInterface) => {
    await queryInterface.dropTable(CUSTOMER_TABLE);
  },
};

Migraci贸n change-user-id.js:

'use strict';

const { CUSTOMER_TABLE } = require('../models/customer.model');
const { DataTypes } = require('sequelize');

module.exports = {
  up: async (queryInterface) => {
    await queryInterface.changeColumn(CUSTOMER_TABLE, 'user_id', {
      field: 'user_id',
      allowNull: false,
      type: DataTypes.INTEGER,
      unique: true,
    });
  },

  down: async (queryInterface) => {
    // await queryInterface.dropTable(CUSTOMER_TABLE);
  },
};

Migraci贸n order.js:

'use strict';

const { ORDER_TABLE } = require('../models/order.model');
const { CUSTOMER_TABLE } = require('../models/customer.model');
const { DataTypes, Sequelize } = require('sequelize');

module.exports = {
  up: async (queryInterface) => {
    await queryInterface.createTable(ORDER_TABLE, {
      id: {
        allowNull: false,
        autoIncrement: true,
        primaryKey: true,
        type: DataTypes.INTEGER,
      },
      customerId: {
        field: 'customer_id',
        allowNull: false,
        type: DataTypes.INTEGER,
        references: {
          model: CUSTOMER_TABLE,
          key: 'id',
        },
        onUpdate: 'CASCADE',
        onDelete: 'SET NULL',
      },
      createdAt: {
        allowNull: false,
        type: DataTypes.DATE,
        field: 'created_at',
        defaultValue: Sequelize.NOW,
      },
    });
  },

  down: async (queryInterface) => {
    await queryInterface.dropTable(ORDER_TABLE);
  },
};

Error ''VIRTUAL'

Con la configuraci贸n de ssl del video no me ha funcionado. Parece que para un pool si sirve poner:

dialectOptions: {
            ssl: {
                rejectUnauthorized: false
            }
        }

Pero me segu铆a dando un error de pg_hba.conf y ssl en off. He tenido que a帽adir:

dialectOptions: {
            ssl: {
                require: true,
                rejectUnauthorized: false
            }
        }

Me segu铆a falando y encontr茅 un aporte que indicaba que hab铆a que definir el modo:

heroku config:set PGSSLMODE=no-verify

Con este curso me he dado cuenta de que el Frontend es definitivamente m谩s f谩cil que el Backend 馃槄

La funcionalidad del rango de precios de productos qued贸 mal 馃槮

Uff ya quiero trabajar en otro proyecto igual.

No me quedar茅 con la duda. Lo que entiendo es que las migraciones en la pratica nos servir谩n para que se creen todas las tablas en nuestra base de datos nueva. 驴Estoy bien en eso?

Si desde el inicio ya tengo claro como quiero que sea mi base de datos y no tengo que hacer fixes porque desde el inicio se lo que se iba a presentar. 驴Podr铆a simplemente eliminar la creaci贸n de crear el rol puesto que si ya estaba en el esquema en la migraci贸n anterior se crear铆a?

No se si me hago entender, me gustar铆a salir de esa duda.

Heroku no tienes planes gratuito a la fecha! hice mi deploy en render el repositorio de github

Una opci贸n de deploy es Railway yo lo use as铆:

  • Primero deben de configuarar las migraciones en mi caso borre todas las migraciones y solo cree una:
'use strict';
const { DataTypes, Sequelize } = require('sequelize');
const { USER_TABLE, UserSchema } = require('./../models/user.model')
const { CUSTOMER_TABLE, CustomerSchema } = require('./../models/customer.model')
const { CATEGORY_TABLE, CategorySchema } = require('./../models/category.model')
const { PRODUCT_TABLE, ProductSchema } = require('./../models/product.model')
const { ORDER_TABLE } = require('./../models/order.model')
const { OrderProductSchema, ORDER_PRODUCT_TABLE } = require('./../models/order-product')



module.exports = {
  up: async (queryInterface) => {
    await queryInterface.createTable(USER_TABLE, UserSchema);
    await queryInterface.createTable(CUSTOMER_TABLE, CustomerSchema);
    await queryInterface.createTable(CATEGORY_TABLE, CategorySchema);
    await queryInterface.createTable(PRODUCT_TABLE, ProductSchema);
    await queryInterface.createTable(ORDER_TABLE, {
      id: {
        allowNull: false,
        autoIncrement: true,
        primaryKey: true,
        type: DataTypes.INTEGER
      },
      customerId: {
        field: 'customer_id',
        allowNull: false,
        type: DataTypes.INTEGER,
        references: {
          model: CUSTOMER_TABLE,
          key: 'id'
        },
        onUpdate: 'CASCADE',
        onDelete: 'SET NULL'
          },
      createdAt: {
        allowNull: false,
        type: DataTypes.DATE,
        field: 'created_at',
        defaultValue: Sequelize.NOW,
        },

    });
    await queryInterface.createTable(ORDER_PRODUCT_TABLE, OrderProductSchema);

  },

  down: async (queryInterface) => {
    await queryInterface.dropTable(USER_TABLE)
    await queryInterface.dropTable(CUSTOMER_TABLE)
    await queryInterface.dropTable(PRODUCT_TABLE)
    await queryInterface.dropTable(CATEGORY_TABLE)
    await queryInterface.dropTable(ORDER_TABLE)
    await queryInterface.dropTable(ORDER_PRODUCT_TABLE)
  }
};
  • Se crean un archivo Dockerfile en la ra铆z del proyecto, ya que Railway solo puede ejecutar este archivo de docker:
    Dockerfile
FROM node:16 AS build

RUN mkdir -p /usr/src/app

WORKDIR /usr/src/app

COPY package*.json ./
RUN npm ci

COPY . .

RUN npm run migrations:run

EXPOSE 8080

CMD ["npm", "start"]
  • Primero creamos una DB en Railway y copiamos la URL de conexi贸n en su apartado de conexi贸n
  • En esta parte debemos ir al archivo .env y pegar la url de conexi贸n:
    .env
DATABASE_URL='urlderailway'
  • En nuestro .gitignore eliminamos el archivo .env y lo subimos a un repo de github. Y creamos el proyecto para nuestra aplicai贸n en Railway

  • Creamos el servicio y deber铆a correr la migraci贸n sin problemas.

  • NOTA: esta opci贸n nos dejar谩 hacer el deploy pero es una mala practica ya que estaremos dejando expuesta nuestra varible de entorno al subir el archivo .env . Por lo que es solo una buena opci贸n para aprender pero para producci贸n no.
    No se si se podr谩 ya que al momento de crear el proyecto del servicio railway nos permite pasarle variables de entorno pero por alguna raz贸n (en mi caso) no detectaba o no le llegaba la variable de entorno, es por eso, por el momento que lo solucione as铆, si alguien pudo subirlo en Railway espero su feedback. Gracias.

DE ESTA MANERA SUBIMOS A Railway:
De esta manera pude yo subirlo a Railway sin borrar el .env del .gitignore Configure las migraciones a una sola:

'use strict';

const { DataTypes, Sequelize } = require('sequelize');
const { USER_TABLE } = require('./../models/user.model');
const { CUSTOMER_TABLE } = require('./../models/customer.model');
const { CATEGORY_TABLE } = require('./../models/category.model');
const { PRODUCT_TABLE } = require('./../models/product.model');
const { ORDER_TABLE } = require('./../models/order.model');
const { ORDER_PRODUCT_TABLE } = require('./../models/order-product.model');

/** @type {import('sequelize-cli').Migration} */
module.exports = {
  up: async (queryInterface) => {
    await queryInterface.createTable(USER_TABLE, {
      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: 'create_at',
        defaultValue: Sequelize.NOW,
      },
    });
    await queryInterface.createTable(CUSTOMER_TABLE, {
      id: {
        allowNull: false,
        autoIncrement: true,
        primaryKey: true,
        type: DataTypes.INTEGER,
      },
      firstName: {
        allowNull: false,
        type: DataTypes.STRING,
        field: 'first_name',
      },
      lastName: {
        allowNull: false,
        type: DataTypes.STRING,
        field: 'last_name',
      },
      phone: {
        allowNull: true,
        type: DataTypes.STRING,
      },
      createdAt: {
        allowNull: false,
        type: DataTypes.DATE,
        field: 'create_at',
        defaultValue: Sequelize.NOW,
      },
      userId: {
        field: 'user_id',
        allowNull: false,
        type: DataTypes.INTEGER,
        references: {
          model: USER_TABLE,
          key: 'id',
        },
        onUpdate: 'CASCADE',
        onDelete: 'SET NULL',
      },
    });
    await queryInterface.createTable(CATEGORY_TABLE, {
      id: {
        allowNull: false,
        autoIncrement: true,
        primaryKey: true,
        type: DataTypes.INTEGER,
      },
      name: {
        allowNull: false,
        unique: true,
        type: DataTypes.STRING,
      },
      image: {
        allowNull: false,
        type: DataTypes.STRING,
      },
      createdAt: {
        allowNull: false,
        defaultValue: Sequelize.NOW,
        field: 'create_at',
        type: DataTypes.DATE,
      },
    });
    await queryInterface.createTable(PRODUCT_TABLE, {
      id: {
        allowNull: false,
        autoIncrement: true,
        primaryKey: true,
        type: DataTypes.INTEGER,
      },
      name: {
        allowNull: false,
        type: DataTypes.STRING,
      },
      image: {
        allowNull: false,
        type: DataTypes.STRING,
      },
      description: {
        allowNull: false,
        type: DataTypes.TEXT,
      },
      price: {
        allowNull: false,
        type: DataTypes.INTEGER,
      },
      createdAt: {
        allowNull: false,
        type: DataTypes.DATE,
        field: 'create_at',
        defaultValue: Sequelize.NOW,
      },
      categoryId: {
        field: 'category_id',
        allowNull: false,
        type: DataTypes.INTEGER,
        references: {
          model: CATEGORY_TABLE,
          key: 'id',
        },
        onUpdate: 'CASCADE',
        onDelete: 'SET NULL',
      },
    });
    await queryInterface.createTable(ORDER_TABLE, {
      id: {
        allowNull: false,
        autoIncrement: true,
        primaryKey: true,
        type: DataTypes.INTEGER,
      },
      customerId: {
        field: 'customer_id',
        allowNull: false,
        type: DataTypes.INTEGER,
        references: {
          model: CUSTOMER_TABLE,
          key: 'id',
        },
        onUpdate: 'CASCADE',
        onDelete: 'SET NULL',
      },
      createdAt: {
        allowNull: false,
        defaultValue: Sequelize.NOW,
        field: 'create_at',
        type: DataTypes.DATE,
      },
    });
    await queryInterface.createTable(ORDER_PRODUCT_TABLE, {
      id: {
        allowNull: false,
        autoIncrement: true,
        primaryKey: true,
        type: DataTypes.INTEGER,
      },
      createdAt: {
        allowNull: false,
        type: DataTypes.DATE,
        field: 'create_at',
        defaultValue: Sequelize.NOW,
      },
      amount: {
        allowNull: false,
        type: DataTypes.INTEGER,
      },
      orderId: {
        field: 'order_id',
        allowNull: false,
        type: DataTypes.INTEGER,
        references: {
          model: ORDER_TABLE,
          key: 'id',
        },
        onUpdate: 'CASCADE',
        onDelete: 'SET NULL',
      },
      productId: {
        field: 'product_id',
        allowNull: false,
        type: DataTypes.INTEGER,
        references: {
          model: PRODUCT_TABLE,
          key: 'id',
        },
        onUpdate: 'CASCADE',
        onDelete: 'SET NULL',
      },
    });
  },

  down: async (queryInterface) => {
    await queryInterface.dropTable(USER_TABLE);
    await queryInterface.dropTable(CUSTOMER_TABLE);
    await queryInterface.dropTable(CATEGORY_TABLE);
    await queryInterface.dropTable(PRODUCT_TABLE);
    await queryInterface.dropTable(ORDER_TABLE);
    await queryInterface.dropTable(ORDER_PRODUCT_TABLE);
  },
};

Se crean un archivo **Dockerfile ** en la ra铆z del proyecto:

FROM node:16 AS build

RUN mkdir -p /usr/src/app

WORKDIR /usr/src/app

ARG NODE_ENV
ARG DATABASE_URL

ENV NODE_ENV=$NODE_ENV
ENV DATABASE_URL=$DATABASE_URL

COPY package*.json ./
RUN npm ci

COPY . .

RUN npm run migrations:run

EXPOSE 8080

CMD ["npm", "start"]

Primero creamos una DB en Railway y copiamos la URL de conexi贸n en su apartado de conexi贸n , le dan a New , luego Database - Postgres y le tiene que quedar como la imagen, Las variables de entorno se configuran automaticamente:

Qu茅 pasaria si, borro la migraci贸n de add-role y dejo que el create-user cree el modelo como esta definido ya con el role?

Tuve un error al crear la migraci贸n ya que me aparecia un error con el autoIncrement en la primera tabla.
El error era el siguente:

ERROR: syntax error at or near "SERIAL"

Se pudo corregir dandole el valor de autoIncrement: false, y se agrega la propiedad de defaultValue: UUIDV4: Quedando de la siguente forma

id: {
        allowNull: false,
        autoIncrement: false,
        primaryKey: true,
        type: DataTypes.STRING,
        defaultValue: UUIDV4,
      } 

Tomen en cuenta cambiar todas los id de este tipo, tambi茅n con la llaves for谩neas.

Esta clase es como un backlog y documento de lecciones aprendidas pero en formato mp4

El contenido del archivo de migraci贸n 煤nica:

'use strict';


const { UserSchema, USER_TABLE } = require('./../models/userModel');
const { CustomerSchema, CUSTOMER_TABLE } = require('./../models/customerModel');
const { ProductSchema, PRODUCT_TABLE } = require('./../models/productModel');
const { CategorySchema, CATEGORY_TABLE } = require('./../models/categoryModel');
const { OrderSchema, ORDER_TABLE } = require('./../models/orderModel');
const { OrderProductSchema, ORDER_PRODUCT_TABLE } = require('./../models/order-productModel');

module.exports = {
  async up (queryInterface) {
    await queryInterface.createTable(USER_TABLE, UserSchema);
    await queryInterface.createTable(CUSTOMER_TABLE, CustomerSchema);
    await queryInterface.createTable(PRODUCT_TABLE, ProductSchema);
    await queryInterface.createTable(CATEGORY_TABLE, CategorySchema);
    await queryInterface.createTable(ORDER_TABLE, OrderSchema);
    await queryInterface.createTable(ORDER_PRODUCT_TABLE, OrderProductSchema);
  },

  async down (queryInterface) {
    await queryInterface.dropTable(USER_TABLE);
    await queryInterface.dropTable(CUSTOMER_TABLE);
    await queryInterface.dropTable(PRODUCT_TABLE);
    await queryInterface.dropTable(CATEGORY_TABLE);
    await queryInterface.dropTable(ORDER_TABLE);
    await queryInterface.dropTable(ORDER_PRODUCT_TABLE);
  }
};