Duplicate data between models and migrations

Viewed 1518

I'm learning Sequelize and there is something that I found quite strange, so I think that I'm doing something wrong.

This is my migration for a simple Posts table :

'use strict';
module.exports = {
    up: (queryInterface, Sequelize) => {
        return queryInterface.createTable('Posts', {
            id: {
                allowNull: false,
                autoIncrement: true,
                primaryKey: true,
                type: Sequelize.INTEGER
            },
            title: {
                type: Sequelize.STRING,
                allowNull: false,
            },
            content: {
                type: Sequelize.TEXT,
                allowNull: false,
            },
            authorId: {
                type: Sequelize.INTEGER,
                onDelete: 'CASCADE',
                allowNull: false,
                references: {model: 'Users', key: 'id'}
            },
            publishedAt: {
                type: Sequelize.DATE,
                allowNull: true
            },
            createdAt: {
                allowNull: false,
                type: Sequelize.DATE
            },
            updatedAt: {
                allowNull: false,
                type: Sequelize.DATE
            }
        });
    },
    down: (queryInterface, Sequelize) => {
        return queryInterface.dropTable('Posts');
    }
};

Another little question here, do I have to specify allowNull: false for the title and the content if I don't want them to be null. I think yes, but many projects I saw don't specify it.

This is the Post model :

'use strict';
module.exports = (sequelize, DataTypes) => {
    const Post = sequelize.define('Post', {
        id: {
            allowNull: false,
            autoIncrement: true,
            primaryKey: true,
            type: DataTypes.INTEGER
        },
        title: {
            type: DataTypes.STRING,
            allowNull: false,
        },
        content: {
            type: DataTypes.TEXT,
            allowNull: false,
        },
        publishedAt: {
            type: DataTypes.DATE,
            allowNull: true
        },
    }, {
        classMethods: {
            associate: function (models) {
                Post.belongsTo(models.User, {
                    onDelete: 'CASCADE',
                    foreignKey: {
                        fieldName: 'authorId',
                        allowNull: false
                    }
                });
            }
        }
    });

    return Post;
};

I repeted the same data between to file... I come from Laravel so maybe it's usual in the NodeJS world to do things like these.

4 Answers

To avoid code duplication between models and migrations, use models inside migrations as follows:

'use strict';
const { User } = require('../models');
module.exports = {
    up: (queryInterface, Sequelize) => {
        return User.sync();
        // return queryInterface.createTable('user', { id: Sequelize.INTEGER });
    },

    down: (queryInterface, Sequelize) => {
        return queryInterface.dropTable('user');
    }
};

EDIT:

This is a good option for adding new tables only!

Caution for "{ alter: true }"! When changing existing columns, be aware that sequelize may not recognise a column rename and will perform two "DROP" and "ADD" operations instead of just one "CHANGE". So, for updating schema, better use queryInterface.renameColumn and queryInterface.changeColumn or raw queries.

.sync()

queryInterface

raw queries

  1. If you want your data not to be null it is a good practice to add DB constraints even though it is not mandatory and you can enforce that in your code.

  2. Regarding your second question, short answer is yes. In your case you are duplicating your code. But it is most likely that you will add or modify your table schema in the future which will cause your model to look different from your first migration file. Remember you don't change a migration file after it ran on production since it runs only once. Any time you want to change your table schema you will have to create a new migration file.

I want also to help future visitors

@Wizix, allowNull is important when you want to avoid empty input in the database. it is validation on the server-side.

Example:

const User = db.define('users', {
  fullname: {
    type: Sequelize.STRING(50),
    allowNull: false,
    validate: {
      notEmpty: {
        args: true,
        msg: 'Please provide fullname',
      },
    },
  }
})

I expect user input to not be empty.

  allowNull in models validate input before processed to a database

  allowNull in migration is the last checking validation where we decide to save to a database or to reject the user input.

duplication of data

I found it necessary to have both conditions validating inputs.

Related