Можно ли обновить существующие данные в базе данных postgresql в процессе миграции с помощью sequelize? - PullRequest
0 голосов
/ 07 ноября 2019

Я пытаюсь добавить поле в модель, используя переход с секвелированием, и мне нужно обновить данные в рамках миграции "вверх". Однако вызовы базы данных для обновления данных в процессе миграции не завершаются или выдают ошибку, они просто зависают.

Я пытаюсь добавить поле registrationType в существующую модель в моей базе данных. Это поле не должно быть нулевым, поэтому мне нужно добавить пропу 'allowNull: false'. Старые регистрации, у которых еще нет набора registrationType, должны быть обновлены до нужного типа с использованием данных, которые уже присутствуют в модели. Для этого мне нужно получить доступ к полю идентификатора в модели, получить связанный объект (регистрационные ссылки на местоположение, которое имеет 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 (). Может кто-нибудь сказать мне, как я должен это сделать?

1 Ответ

1 голос
/ 07 ноября 2019

Обновление: Как обсуждалось в чате , нам нужно разделить 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)
    }
}
...