是否可以使用 sequelize 在迁移中更新 postgresql 数据库中的现有数据
Is it possible to update existing data in postgresql database in a migration using sequelize
我正在尝试使用 sequelize 迁移向模型添加字段,并且需要从 'up' 迁移中更新数据。但是,调用数据库以更新迁移中的数据不会完成或引发错误,它们只是挂起。
我正在尝试将 registrationType
字段添加到我数据库中的现有模型。该字段不应为空,因此我需要添加 'allowNull: false' 属性。尚未设置 registrationType
的旧注册应使用模型中已存在的数据更新为正确的类型。为此,我需要访问模型中的 ID 字段,获取链接对象(指向某个位置的注册链接,其中包含 locationtype
)并使用它来确定 registrationType
。我将代码添加到迁移中,就好像它是更新某些数据的正常数据库操作一样,但这些调用不会 return 或引发错误。
我不能(也不想)使用默认值,因为应该根据现有数据为每个注册确定该值(添加默认值会使 allowNull 属性过时)。
我的方法:
- 添加没有 'allowNull' 约束的列(使用 addColumn)
- 更新所有现有数据
- 添加 'allowNull' 约束(使用 changeColumn)
"use strict";
/*const db = require("../models");
const Registration = db.Registration;
const Site = db.Site;
const Location = db.Location;
*/
const REGISTATION_MODEL = "Registrations";
module.exports = {
up: async (queryInterface, Sequelize) => {
const transaction = await queryInterface.sequelize.transaction();
try {
const Registration = await queryInterface.sequelize.import(
"../models/registration.js"
);
const Site = await queryInterface.sequelize.import(
"../models/site.js"
);
const Location = await queryInterface.sequelize.import(
"../models/location.js"
);
await queryInterface.addColumn(
REGISTATION_MODEL,
"registrationType",
{
type: Sequelize.STRING
},
{ transaction }
);
console.log(
" * Column added, going to update existing registrations."
);
const registrations = await Registration.findAll();
console.log(
`\tFound ${registrations.length} registrations to be updated.`
);
for await (const registration of registrations) {
const site = await Site.findByPk(registration.SiteId);
const location = await Location.findByPk(site.LocationId);
await registration.update(
{
registrationType: location.locationType
},
{ transaction }
);
}
console.log(`\tUpdated ${registrations.length} registrations.`);
console.log(" * Adding 'allowNull:false' to field.");
//allowNull: false
await queryInterface.changeColumn(
REGISTATION_MODEL,
"registrationType",
{ type: Sequelize.STRING, allowNull: false },
{ transaction: t }
);
await transaction.commit();
} catch (ex) {
await transaction.rollback();
console.error("Something went wrong: ", ex);
}
},
down: (queryInterface, Sequelize) => {
return queryInterface.removeColumn(
REGISTATION_MODEL,
"registrationType"
);
}
};
输出:
Loaded configuration file "config/config.json".
Using environment "development".
== 20191107134514-add-registration-types: migrating =======
* Column added, going to update existing registrations.
然后挂起。
此处显示的代码不会产生任何错误,也不会产生任何输出。我添加了 console.log 语句,并再次 运行 迁移,这表明代码在第一次 findAll() 调用时挂起。
谁能告诉我该怎么做?
更新: 正如 chat 中所讨论的,我们需要将 addColumn、changeColumn 和更新查询分离到单独的文件中。由于我们不能 运行 所有这些都在同一个事务下,因为它们影响相同的 tables.
如果您想 await
在迁移函数中,您需要使 up/down
函数异步并且 运行 您的事务也使用 await 和 async:
以下是仅用于更新 table 的迁移文件。为 addColumn 和 changeColumn 创建单独的迁移。 运行 他们的顺序是:
- 添加列
- 更新Table
- 更改列
迁移 table 更新:
up: async (queryInterface, Sequelize) => {
// declare transaction outside try catch so it is available in both
const transaction = await queryInterface.sequelize.transaction()
try {
// No need to use transactions for read operations
const registrations = await Registration.findAll()
// using for...of loop which supports awaiting inside it
for await (const registration of registrations) {
const site = await Site.findByPk(registration.SiteId)
const location = await Location.findByPk(site.LocationId)
// Make sure to await on all sequelize methdos
await registration.update({ registrationType: location.locationType })
}
// Commit transaction if no error occurs
await transaction.commit()
} catch (error) {
// Rollback transaction if error occurs
await transaction.rollback()
console.error("Something went wrong: ", ex)
}
}
我正在尝试使用 sequelize 迁移向模型添加字段,并且需要从 'up' 迁移中更新数据。但是,调用数据库以更新迁移中的数据不会完成或引发错误,它们只是挂起。
我正在尝试将 registrationType
字段添加到我数据库中的现有模型。该字段不应为空,因此我需要添加 'allowNull: false' 属性。尚未设置 registrationType
的旧注册应使用模型中已存在的数据更新为正确的类型。为此,我需要访问模型中的 ID 字段,获取链接对象(指向某个位置的注册链接,其中包含 locationtype
)并使用它来确定 registrationType
。我将代码添加到迁移中,就好像它是更新某些数据的正常数据库操作一样,但这些调用不会 return 或引发错误。
我不能(也不想)使用默认值,因为应该根据现有数据为每个注册确定该值(添加默认值会使 allowNull 属性过时)。 我的方法: - 添加没有 'allowNull' 约束的列(使用 addColumn) - 更新所有现有数据 - 添加 'allowNull' 约束(使用 changeColumn)
"use strict";
/*const db = require("../models");
const Registration = db.Registration;
const Site = db.Site;
const Location = db.Location;
*/
const REGISTATION_MODEL = "Registrations";
module.exports = {
up: async (queryInterface, Sequelize) => {
const transaction = await queryInterface.sequelize.transaction();
try {
const Registration = await queryInterface.sequelize.import(
"../models/registration.js"
);
const Site = await queryInterface.sequelize.import(
"../models/site.js"
);
const Location = await queryInterface.sequelize.import(
"../models/location.js"
);
await queryInterface.addColumn(
REGISTATION_MODEL,
"registrationType",
{
type: Sequelize.STRING
},
{ transaction }
);
console.log(
" * Column added, going to update existing registrations."
);
const registrations = await Registration.findAll();
console.log(
`\tFound ${registrations.length} registrations to be updated.`
);
for await (const registration of registrations) {
const site = await Site.findByPk(registration.SiteId);
const location = await Location.findByPk(site.LocationId);
await registration.update(
{
registrationType: location.locationType
},
{ transaction }
);
}
console.log(`\tUpdated ${registrations.length} registrations.`);
console.log(" * Adding 'allowNull:false' to field.");
//allowNull: false
await queryInterface.changeColumn(
REGISTATION_MODEL,
"registrationType",
{ type: Sequelize.STRING, allowNull: false },
{ transaction: t }
);
await transaction.commit();
} catch (ex) {
await transaction.rollback();
console.error("Something went wrong: ", ex);
}
},
down: (queryInterface, Sequelize) => {
return queryInterface.removeColumn(
REGISTATION_MODEL,
"registrationType"
);
}
};
输出:
Loaded configuration file "config/config.json".
Using environment "development".
== 20191107134514-add-registration-types: migrating =======
* Column added, going to update existing registrations.
然后挂起。
此处显示的代码不会产生任何错误,也不会产生任何输出。我添加了 console.log 语句,并再次 运行 迁移,这表明代码在第一次 findAll() 调用时挂起。 谁能告诉我该怎么做?
更新: 正如 chat 中所讨论的,我们需要将 addColumn、changeColumn 和更新查询分离到单独的文件中。由于我们不能 运行 所有这些都在同一个事务下,因为它们影响相同的 tables.
如果您想 await
在迁移函数中,您需要使 up/down
函数异步并且 运行 您的事务也使用 await 和 async:
以下是仅用于更新 table 的迁移文件。为 addColumn 和 changeColumn 创建单独的迁移。 运行 他们的顺序是:
- 添加列
- 更新Table
- 更改列
迁移 table 更新:
up: async (queryInterface, Sequelize) => {
// declare transaction outside try catch so it is available in both
const transaction = await queryInterface.sequelize.transaction()
try {
// No need to use transactions for read operations
const registrations = await Registration.findAll()
// using for...of loop which supports awaiting inside it
for await (const registration of registrations) {
const site = await Site.findByPk(registration.SiteId)
const location = await Location.findByPk(site.LocationId)
// Make sure to await on all sequelize methdos
await registration.update({ registrationType: location.locationType })
}
// Commit transaction if no error occurs
await transaction.commit()
} catch (error) {
// Rollback transaction if error occurs
await transaction.rollback()
console.error("Something went wrong: ", ex)
}
}