Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Am i supposed to keep Sequelize models and migrations in sync?

I'm new to Sequelize.js and Databases in general, i haven't used migrations before, but i know that they can be used to make changes to the tables structure in a non-destructive way.

However i'm not sure where to declare column options (notNull, references, validate, ENUM values, etc...)

Should i declare such options in the the model file, or migration file? or both?

Wouldn't adding the options to both model and migration cause duplicate code?

(keep in mind that i'm talking about the initial migrations that create tables to the database, not the migrations that add columns and stuff...)

Any help would be appreciated!

like image 737
Exil Avatar asked May 20 '20 17:05

Exil


Video Answer


2 Answers

I see three options you can take. The first two options might be edge cases but it helps to understand.

Destructive option

You want to prototype a project and you don't mind losing your data, then you could potentially do not care about migration files and synchronize your database according to your model with:

await sequelize.sync({ force: true });

It will execute on all your models:

DROP TABLE IF EXISTS "your_model" CASCADE;
CREATE TABLE IF NOT EXISTS "your_model" (...)

This command can be executed at the start of your application for example.


 Static option

As you mentioned you don't want to add columns and stuff, it's probably a good option.

Now if you don't want to lose data, you could simply use the sync method without the force option:

await sequelize.sync({ });

It will only generate:

CREATE TABLE IF NOT EXISTS "your_model" (...)

Hence, your tables are created according to your models and you don't have to create migration files.

However, if you want to modify your model and it's the most frequent usecase, the new column will not be generated in the table dynamically that's why you need migration scripts.


Flexible option

You will have to define both migration file and your model. That's what the cli does. Here is an example:

# npx sequelize-cli init or create migrations and models folders
npx sequelize-cli model:generate --name User --attributes firstName:string,email:string

Now you will have two more files:

// migrations/<date>-create-user.js
module.exports = {
  up: (queryInterface, Sequelize) => {
    return queryInterface.createTable('Users', {
      id: {
        allowNull: false,
        autoIncrement: true,
        primaryKey: true,
        type: Sequelize.INTEGER
      },
      firstName: {
        type: Sequelize.STRING
      },
      email: {
        type: Sequelize.STRING
      },
      createdAt: {
        allowNull: false,
        type: Sequelize.DATE
      },
      updatedAt: {
        allowNull: false,
        type: Sequelize.DATE
      }
    });
  },
  down: (queryInterface, Sequelize) => {
    // I usually remove this and create the table only if not exists
    return queryInterface.dropTable('Users'); 
  }
};
// models/users.js
module.exports = (sequelize, DataTypes) => {
  const User = sequelize.define('User', {
    firstName: DataTypes.STRING,
    email: DataTypes.STRING
  }, {});
  User.associate = function(models) {
    // associations can be defined here
  };
  return User;
};

You could refactor the code from the migration and the model, however it will be rather cumbersome because some migration files will only add one column, so merging all of them into the model might probably be less clear.

like image 82
L. Meyer Avatar answered Sep 27 '22 17:09

L. Meyer


You should do it in both because as time goes by your models and inital migration will differ from each other. So I suppose you should determine a final structure in models and after that create an initial migration.

like image 21
Anatoly Avatar answered Sep 27 '22 17:09

Anatoly