我刚刚开始使用Sequelize和Sequelize CLI
由于这是一个开发时间,因此经常添加和删除列。将新列添加到现有模型的最佳方法是什么?
例如,我想要一个新列“已完成”到 Todo 模型。我将此列添加到models / todo.js。什么是下一步?
我尝试了sequelize db:migrate
无效:“未执行迁移,数据库架构已更新。”
答案 0 :(得分:37)
如果您使用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
答案 1 :(得分:4)
如果要将多个列添加到同一个表中,请将所有内容包装在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')
]);
}
};
续列https://sequelize.readthedocs.io/en/2.0/api/datatypes/可以支持任何列类型
答案 2 :(得分:2)
要在序列中添加多列
步骤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
答案 3 :(得分:2)
您仍然可以使用带有对象参数的同步功能,该参数带有两个选项,当然是默认选项(不添加值)和实例(添加力或alter属性)。
因此,在这种情况下,您要使用UserModel.sync({ force: true })
:这将创建表,如果表已经存在,则将其首先删除
UserModel.sync({ alter: true })
这将检查数据库中表的当前状态(它具有哪些列,它们的数据类型等),然后在表中执行必要的更改以使其与模式匹配... 使用模型实例时可以使用它 有关更新以及表和模型的更多信息,请查看有关更多功能的文档here
答案 4 :(得分:1)
每个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;
}
}
};
答案 5 :(得分:0)
如果您使用的是vscode,则可以在迁移文件中添加类型定义。这有助于识别QueryInterface并序列化提供的所有方法。
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'
);
}
}
答案 6 :(得分:0)
我认为,如果您在添加或删除列之前先检查特定表中的列,那就太好了。如果该列已经存在,这将消除错误。
'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)
}),
]);
}
};