Как добавить, удалить новые столбцы в Sequelize CLI

Я только начал использовать Sequelize и Sequelize CLI

Поскольку это время разработки, столбцы часто добавляются и удаляются. Какой лучший способ добавить новый столбец к существующей модели?

Например, я хочу создать новый столбец "Завершено" для модели Todo. Я добавлю этот столбец в models / todo.js. Что дальше?

Я пробовал sequelize db:migrate

не работает: «Миграции не выполнялись, схема базы данных уже обновлена»


person Gijo Varghese    schedule 22.09.2017    source источник


Ответы (7)


Если вы используете sequelize-cli, вам необходимо сначала создать миграцию. Это просто файл, который сообщает движку, как обновить базу данных и как откатить изменения в случае, если что-то пойдет не так. Вы всегда должны фиксировать этот файл в своем репозитории.

$ sequelize migration:create --name name_of_your_migration

Файл миграции будет выглядеть так:

module.exports = {
  up: function(queryInterface, Sequelize) {
    // logic for transforming into the new state
    return queryInterface.addColumn(
      'Todo',
      'completed',
     Sequelize.BOOLEAN
    );

  },

  down: function(queryInterface, Sequelize) {
    // logic for reverting the changes
    return queryInterface.removeColumn(
      'Todo',
      'completed'
    );
  }
}

А затем запустите его:

$ sequelize db:migrate
person Maria Ines Parnisari    schedule 22.09.2017
comment
Есть ли для этого документация? - person Gijo Varghese; 22.09.2017
comment
Спасибо. Что, если я хочу добавить несколько столбцов? - person Gijo Varghese; 22.09.2017
comment
И какие документы мне предпочесть? docs.sequelizejs.com или sequelize.readthedocs.io ?? - person Gijo Varghese; 22.09.2017
comment
Для 1. Вы просто добавляете несколько операторов addColumn в функцию up, а затем соответствующие removeColumn в функцию down. - person Maria Ines Parnisari; 22.09.2017
comment
Для 2. Я бы сказал sequelize.readthedocs.io/en/v3. Он поступает прямо из репозитория исходного кода. - person Maria Ines Parnisari; 22.09.2017
comment
Потрясающий. Спасибо :) - person Gijo Varghese; 22.09.2017
comment
Спасибо. Обратите внимание, что вы должны указать имя новой миграции с параметром --name. - person modernator; 21.10.2018
comment
Должен ли я вручную добавить новый столбец в уже существующий файл модели до или после команды миграции? Или сиквелиз добавляет это автоматически? - person Hans; 15.07.2019
comment
@Hans, sequelize не касается файла модели. Поэтому вам следует обновить класс модели после завершения миграции. - person Maria Ines Parnisari; 23.07.2019

Если вы хотите добавить несколько столбцов в одну и ту же таблицу, оберните все в Promise.all() и поместите столбцы, которые вы хотите добавить, в массив:

module.exports = {
  up: (queryInterface, Sequelize) => {
    return Promise.all([
      queryInterface.addColumn(
        'tableName',
        'columnName1',
        {
          type: Sequelize.STRING
        }
      ),
      queryInterface.addColumn(
        'tableName',
        'columnName2',
        {
          type: Sequelize.STRING
        }
      ),
    ]);
  },

  down: (queryInterface, Sequelize) => {
    return Promise.all([
      queryInterface.removeColumn('tableName', 'columnName1'),
      queryInterface.removeColumn('tableName', 'columnName2')
    ]);
  }
};

У вас может быть любой тип столбца, поддерживаемый sequelize https://sequelize.readthedocs.io/en/2.0/api/datatypes/

person thedanotto    schedule 25.03.2019
comment
Также лучше обернуть обещание транзакцией. Вы можете найти пример здесь: docs.sequelizejs.com/manual/migrations.html # migration-скелет - person Pter; 10.07.2019

Чтобы добавить несколько столбцов в продолжение

Шаг 1: создайте пустой перенос

sequelize migration:generate --name custom_name_describing_your_migration

Шаг 2: добавьте столбцы в пустой перенос.

Используйте транзакцию в соответствии с документами https://sequelize.org/master/manual/migrations.html#migration-skeleton:

module.exports = {
    up: (queryInterface, Sequelize) => {
        return queryInterface.sequelize.transaction((t) => {
            return Promise.all([
                queryInterface.addColumn('table_name', 'field_one_name', {
                    type: Sequelize.STRING
                }, { transaction: t }),
                queryInterface.addColumn('table_name', 'field_two_name', {
                    type: Sequelize.STRING,
                }, { transaction: t })
            ])
        })
    },

    down: (queryInterface, Sequelize) => {
        return queryInterface.sequelize.transaction((t) => {
            return Promise.all([
                queryInterface.removeColumn('table_name', 'field_one_name', { transaction: t }),
                queryInterface.removeColumn('table_name', 'field_two_name', { transaction: t })
            ])
        })
    }
};

Шаг 3. запустите перенос

sequelize db:migrate

person GavinBelson    schedule 30.10.2019
comment
Голосование за предоставление прямой ссылки на часть документа о миграции. - person YulePale; 01.12.2019
comment
@Gavin создает миграцию, добавляет новые столбцы в эту миграцию, а затем запускает миграцию, также добавит столбцы в модель? - person MKJ; 06.09.2020
comment
@MKJ он не будет добавлять столбцы в модель. Если вы создадите новую миграцию для новой таблицы и дадите ей атрибуты, она затем сгенерирует модель с заданными атрибутами (столбцами) - person GavinBelson; 07.09.2020

Если вы работаете в vscode, вы можете добавить определение типа в файл миграции. который помогает идентифицировать все методы, которые предоставляют QueryInterface и sequelize.

 module.exports = {
/**
   * @typedef {import('sequelize').Sequelize} Sequelize
   * @typedef {import('sequelize').QueryInterface} QueryInterface
   */

  /**
   * @param {QueryInterface} queryInterface
   * @param {Sequelize} Sequelize
   * @returns
   */
  up: function(queryInterface, Sequelize) {
    // logic for transforming into the new state
    return queryInterface.addColumn(
      'Todo',
      'completed',
     Sequelize.BOOLEAN
    );

  },

  down: function(queryInterface, Sequelize) {
    // logic for reverting the changes
    return queryInterface.removeColumn(
      'Todo',
      'completed'
    );
  }
}

Что обеспечит intellisense, как показано ниже  sequelize intellisense

person NS23    schedule 11.06.2019
comment
это потрясающе! - person tam.teixeira; 16.09.2019
comment
привет @ NS23, какое расширение вы используете? - person John Rey Flores; 04.11.2019
comment
@JohnReyFlores нет необходимости в расширении. Вы можете прочитать статью по ссылке, чтобы лучше понять безопасность типов с помощью jsdoc «Type Safe JavaScript with JSDoc» от TruckJS medium.com/@trukrs/type-safe-javascript-with-jsdoc-7a2a63209b76 - person NS23; 04.11.2019
comment
ОТЛИЧНО, я не знал об этой невероятно полезной функции !! Спасибо - person Magico; 22.04.2020

Вы по-прежнему можете использовать функцию синхронизации, которая принимает параметр объекта с двумя вариантами, конечно, вариант по умолчанию, где вы не добавляете значение, и экземпляр, где вы добавляете атрибут force или alter. Итак, в этом случае вы хотите использовать UserModel.sync({ force: true }): это создает таблицу, сначала удаляя ее, если она уже существует.

UserModel.sync({ alter: true })

Это проверяет текущее состояние таблицы в базе данных (какие столбцы у нее есть, каковы их типы данных и т. Д.), А затем выполняет необходимые изменения в таблице, чтобы она соответствовала режиму ... Вы можете использовать это при использовании экземпляров модели Для получения дополнительной информации об обновлении, а также таблиц и моделей ознакомьтесь с документацией по дополнительным функциям здесь

person BrianDev    schedule 20.07.2020

Предложение Per Pter обернуть Promise в транзакцию, вот пример с использованием async / await и транзакции (из документов с исправлением ошибки при создании индекса):

'use strict';

module.exports = {
    async up(queryInterface, Sequelize) {
        const transaction = await queryInterface.sequelize.transaction();
        try {
            await queryInterface.addColumn(
                'Todo',
                'completed',
                {
                    type: Sequelize.STRING,
                },
                { transaction }
            );

            await queryInterface.addIndex(
                'Todo',
                {
                    fields: ['completed'],
                    unique: true,
                },
                { transaction }
            );

            await transaction.commit();
        } catch (err) {
            await transaction.rollback();
            throw err;
        }
    },

    async down(queryInterface, Sequelize) {
        const transaction = await queryInterface.sequelize.transaction();
        try {
            await queryInterface.removeColumn(
                'Todo',
                'completed',
                { transaction }
            );

            await transaction.commit();
        } catch (err) {
            await transaction.rollback();
            throw err;
        }
    }
};
person Tim Newton    schedule 27.08.2019
comment
почему ты вручную откатываешься? вы можете попробовать попробовать / поймать, когда возникает ошибка, он автоматически откатывается - person tam.teixeira; 16.09.2019

Я думаю, если бы вы проверили свой столбец внутри конкретной таблицы перед добавлением или удалением, это было бы здорово. Это устранит ошибку, если столбец уже существует.

'use strict';

module.exports = {
  // result_description
  up: async (queryInterface, Sequelize) => {
    let tableName = 'yourTableName';
    let columnName1 = 'columnName1';
    let columnName2 = 'columnName1';
    return Promise.all([
      queryInterface.describeTable(tableName)
        .then(tableDefinition => {
          if (tableDefinition.columnName1) return Promise.resolve();

          return queryInterface.addColumn(
            tableName,
            columnName1,
            {
              type: Sequelize.INTEGER,
              allowNull: false
            }
          );
        }),
      queryInterface.describeTable(tableName)
        .then(tableDefinition => {
          if (tableDefinition.columnName2) return Promise.resolve();

          return queryInterface.addColumn(
            tableName,
            columnName2,
            {
              type: Sequelize.STRING,
              allowNull: false
            }
          );
        })
    ]);
  },

  down: (queryInterface, Sequelize) => {

    let tableName = 'TestList';
    let columnName1 = 'totalScore';
    let columnName2 = 'resultDescription';
    return Promise.all([
      queryInterface.describeTable(tableName)
        .then(tableDefinition => {
          if (tableDefinition.columnName1) return Promise.resolve();
          return queryInterface.removeColumn(tableName, columnName1)
        }),
      queryInterface.describeTable(tableName)
        .then(tableDefinition => {
          if (tableDefinition.columnName1) return Promise.resolve();
          return queryInterface.removeColumn(tableName, columnName2)
        }),
    ]);
  }
};
person Srujal Patel    schedule 26.03.2020