如何在 Sequelize CLI 中添加、删除新列

Posted

技术标签:

【中文标题】如何在 Sequelize CLI 中添加、删除新列【英文标题】:How to Add, Delete new Columns in Sequelize CLI 【发布时间】:2018-03-03 14:37:06 【问题描述】:

我刚刚开始使用 Sequelize 和 Sequelize CLI

由于是开发时期,经常会增加和删除列。向现有模型添加新列的最佳方法是什么?

例如,我想将一个新列 'completed' 改为 Todo 模型。我将此列添加到 models/todo.js。下一步是什么?

我试过sequelize db:migrate

不工作:“没有执行迁移,数据库架构已经是最新的。”

【问题讨论】:

【参考方案1】:

您仍然可以使用带有对象参数的同步功能,其中有两个选项当然是您不添加值的默认选项和添加强制或更改属性的实例。 所以在这种情况下你想使用UserModel.sync( force: true ):这会创建表,如果它已经存在则首先删除它

UserModel.sync( alter: true )

这会检查数据库中表的当前状态(它有哪些列,它们的数据类型是什么等),然后在表中执行必要的更改以使其与模式匹配... 使用模型实例时可以使用它 有关更新以及表格和模型的更多信息,请查看有关更多功能的文档here

【讨论】:

【参考方案2】:

我认为,如果您在添加或删除特定表之前检查您的列,那就太好了。如果该列已存在,这将消除错误。

'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)
        ),
    ]);
  
;

【讨论】:

【参考方案3】:

在 sequelize 中添加多列

第一步:生成空迁移

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

【讨论】:

赞成直接链接到文档的迁移部分。 @Gavin 创建迁移,向此迁移添加新列,然后运行迁移也会将列添加到模型中? @MKJ 它不会向模型添加列。如果您为新表生成新迁移并为其赋予属性,那么它将生成具有给定属性(列)的模型【参考方案4】:

根据 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;
        
    
;

【讨论】:

为什么要手动回滚?你可以搭上try/catch,当出现错误时会自动回滚【参考方案5】:

如果你在 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'
    );
  

这将提供如下所示的智能感知

【讨论】:

太棒了! 嗨@NS23,你用的是什么扩展? @JohnReyFlores 不需要任何扩展。您可以阅读链接中的文章以更好地理解类型安全与 jsdoc “Type Safe javascript with JSDoc” by TruckJS medium.com/@trukrs/type-safe-javascript-with-jsdoc-7a2a63209b76 太棒了我不知道这个令人难以置信的有用功能!谢谢【参考方案6】:

如果您想在同一个表中添加多个列,请将所有内容包装在 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/ 支持的任何列类型都可以

【讨论】:

另外,使用事务包装承诺会更好。你可以在这里找到一个例子:docs.sequelizejs.com/manual/migrations.html#migration-skeleton【参考方案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

【讨论】:

有这方面的文档吗? 我应该更喜欢哪些文档? docs.sequelizejs.com 或 sequelize.readthedocs.io ?? 对于1.您只需在up函数中添加多个addColumn语句,然后在down函数中添加相应的removeColumns。 对于 2。我会说 sequelize.readthedocs.io/en/v3。它直接来自源代码存储库。 谢谢。请注意,您必须使用 --name 参数指定新迁移的名称。

以上是关于如何在 Sequelize CLI 中添加、删除新列的主要内容,如果未能解决你的问题,请参考以下文章

如何在使用 Sequelize 更改列或添加新列时更新迁移文件

更改模型后如何创建 Sequelize cli db 迁移

在 sequelize 返回值中删除连接表数据

删除 sequelize 迁移中的约束

使用 vue-cli3 删除插件

在 Node 14 中使用 sequelize-cli,类型为:module