我刚刚开始使用 Sequelize 和 Sequelize CLI
由于是开发时间,所以经常会添加和删除列。向现有模型添加新列的最佳方法是什么?
例如,我想将一个新列 '完成' 到Todo模型。我将此列添加到 models/todo.js。下一步是什么?
我试过sequelize db:migrate
不工作:“没有执行迁移,数据库模式已经是最新的。”
我刚刚开始使用 Sequelize 和 Sequelize CLI
由于是开发时间,所以经常会添加和删除列。向现有模型添加新列的最佳方法是什么?
例如,我想将一个新列 '完成' 到Todo模型。我将此列添加到 models/todo.js。下一步是什么?
我试过sequelize db:migrate
不工作:“没有执行迁移,数据库模式已经是最新的。”
如果您使用的是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
如果要将多个列添加到同一个表中,请将所有内容包装在 a 中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/支持的任何列类型
在 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
如果你在 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'
);
}
}
您仍然可以使用带有两个选项的对象参数的同步函数,当然一个是您不添加值的默认选项,另一个是您添加强制或更改属性的实例。所以在这种情况下你想使用UserModel.sync({ force: true })
:这将创建表,如果它已经存在则首先删除它
UserModel.sync({ alter: true })
这会检查数据库中表的当前状态(它有哪些列,它们的数据类型是什么等),然后在表中执行必要的更改以使其与模式匹配......你可以使用这个当您使用模型实例有关更新以及表和模型的更多信息时,请在此处查看有关更多功能的文档
我认为,如果您在添加或删除特定表之前检查您的列,那就太好了。如果该列已存在,这将消除错误。
'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)
}),
]);
}
};
根据 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;
}
}
};