【问题标题】:Is it possible to update existing data in postgresql database in a migration using sequelize是否可以使用 sequelize 在迁移中更新 postgresql 数据库中的现有数据
【发布时间】:2020-03-04 05:41:40
【问题描述】:

我正在尝试使用 sequelize 迁移向模型添加字段,并且需要从“向上”迁移中更新数据。但是,在迁移中调用数据库以更新数据不会完成或引发错误,它们只是挂起。

我正在尝试将registrationType 字段添加到我数据库中的现有模型中。这个字段不应该为空,所以我需要添加 'allowNull: false' 属性。尚未设置 registrationType 的旧注册应使用模型中已存在的数据更新为正确的类型。为此,我需要访问模型中的 ID 字段,获取链接对象(注册链接到具有locationtype 的位置)并使用它来确定registrationType。我在迁移中添加了代码,就好像它是更新某些数据的正常数据库操作一样,但是这些调用不会返回或抛出错误。

我不能(也不想)使用默认值,因为应该根据现有数据为每个注册确定该值(添加默认值将使 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() 调用时挂起。 谁能告诉我该怎么做?

【问题讨论】:

    标签: javascript node.js sequelize.js database-migration sequelize-cli


    【解决方案1】:

    更新: 正如chat 中所讨论的,我们需要将 addColumn、changeColumn 和更新查询分离到单独的文件中。因为我们不能在同一个事务下运行所有​​这些,因为它们会影响同一张表。

    如果您想在迁移函数中使用 await,您需要使 up/down 函数异步并使用 await 和 async 运行您的事务:

    以下是仅用于更新表的迁移文件。为 addColumn 和 changeColumn 创建单独的迁移。按顺序运行它们:

    1. 添加列
    2. 更新表
    3. 更改列

    表更新迁移:

    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)
        }
    }
    

    【讨论】:

    • 感谢您的回答。以这种方式导入模型仍然会让我得到一个挂起的查询,与原始问题中描述的情况相同。
    • 您在控制台中获得的最后一个输出是什么?
    • const registrations = await Registration.findAll()前一行console.log语句的输出
    • 您将async await 与返回的Promises 混合在一起,这可能会导致问题。稍后我会在答案中提供一个可能正确的代码。同时参考这个Sequelize Migrations
    • 我已根据您的建议更新了我的代码,但输出保持不变。有关运行迁移的更新代码和输出,请参阅问题。
    猜你喜欢
    • 2015-06-27
    • 2021-09-16
    • 1970-01-01
    • 1970-01-01
    • 2015-08-02
    • 2015-06-04
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多