You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何用Umzug执行Sequelize-CLI迁移文件?迁移异常排查

问题描述

我注释掉了sequelize.sync以避免自动生成表,目的是验证dbmigrate.js的有效性。但现在调用该文件时仅创建sequelizemeta表,执行npx sequelize db:migrate命令却能正常生成其他业务表,全程无任何报错,无法定位问题所在。


初始化数据库并调用迁移、种子文件的文件(data/index.js)

// data/index.js

const config = require('config');

const {
    getLogger,
} = require('../core/logging');

const {
    sequelize,
} = require('./models');
const connectionTest = require('./tools/dbtest');
const migrate = require('./tools/dbmigrate');
//const seed = require('./tools/dbseed');


const isDevelopment = () => {
    return config.get('env') === 'development' ? true : false;
};

async function initializeData() {
    // Syncs the database and uses alter to push the model changes if the table already exists
    /*
    await sequelize.sync({
        alter: true,
    });
    */

    // Test the Connection
    await connectionTest();

    // Migrate
    await migrate();

    // Seed
    //if (isDevelopment()) await seed();
}

async function shutdownData() {
    const logger = getLogger();
    logger.info('Shutting down database connection');
    await sequelize.close();
    logger.info('Database connection closed');
}

module.exports = {
    initializeData,
    shutdownData,
};

Sequelize实例创建代码(data/models/index.js)

// data/models/index.js

'use strict';
// Generated using npx sequelize init
const fs = require('fs');
const path = require('path');

const Sequelize = require('sequelize');
const basename = path.basename(__filename);
// Added by me
const config = require('config');

// Deconstructing database variables
const [DATABASE_NAME, DATABASE_USERNAME, DATABASE_PASSWORD, DATABASE_HOST, DATABASE_DIALECT, DATABASE_PORT] = [config.get('database.name'), config.get('database.username'), config.get('database.password'), config.get('database.host'), config.get('database.dialect'), config.get('database.port')];

const db = {};

// Initializing the Sequelize database
// npx sequelize init puts there database in the models folder,
// for that reason I keep it here (data/models/index.js) instead of moving it to the index.js in the data folder
const sequelize = new Sequelize(
    DATABASE_NAME,
    DATABASE_USERNAME,
    DATABASE_PASSWORD, {
        host: DATABASE_HOST,
        dialect: DATABASE_DIALECT,
        port: DATABASE_PORT,
        logging: true,
    },
);

fs
    .readdirSync(__dirname)
    .filter((file) => {
        return (file.indexOf('.') !== 0) && (file !== basename) && (file.slice(-3) === '.js');
    })
    .forEach((file) => {
        const model = require(path.join(__dirname, file))(sequelize, Sequelize.DataTypes);
        db[model.name] = model;
    });

Object.keys(db).forEach((modelName) => {
    if (db[modelName].associate) {
        db[modelName].associate(db);
    }
});

db.sequelize = sequelize;

module.exports = db;

迁移代码(问题所在,data/tools/dbmigrate.js)

// data/tools/dbmigrate.js
const {
    Umzug,
    SequelizeStorage,
} = require('umzug');

const {
    getLogger,
} = require('../../core/logging');
const {
    sequelize,
} = require('../models/');


module.exports = async function migrate() {
    const logger = getLogger();

    const migrator = new Umzug({
        migrations: {
            glob: '{../migrations/*.js}',
        },

        context: sequelize.getQueryInterface(),
        storage: new SequelizeStorage({
            sequelize: sequelize,
        }),
        logger: console,
    });

    let migrationSuccessful = true;
    try {
        await migrator.up();
        logger.info('Succesful migration');
    } catch (error) {
        migrationSuccessful = false;
        logger.error('Error while migrating the database', {
            error,
        });
    }

    if (!migrationSuccessful) {
        try {
            await migrator.down();
            logger.info('Succesful migration after reverting the latest migration');
        } catch (error) {
            logger.error('Error while migrating the database', {
                error,
            });
        }
        throw new Error('Migrations failed');
    }

};

迁移文件示例(由Sequelize-CLI生成,data/migrations/20221121195900-create-user.js)

// data/migrations/20221121195900-create-user.js
'use strict';
/** @type {import('sequelize-cli').Migration} */
module.exports = {
    async up(queryInterface, DataTypes) {
        await queryInterface.createTable('users', {
            userID: {
                primaryKey: true,
                type: DataTypes.UUID,
                allowNull: false,
            },
            firstName: {
                type: DataTypes.STRING,
                allowNull: false,
            },
            lastName: {
                type: DataTypes.STRING,
                allowNull: false,
            },
            email: {
                type: DataTypes.STRING,
                allowNull: false,
            },
            password: {
                type: DataTypes.STRING,
                allowNull: false,
            },
            dateOfBirth: {
                type: DataTypes.DATE,
                allowNull: false,
            },
            gender: {
                type: DataTypes.ENUM('M', 'F'),
                allowNull: false,
            },
            createdAt: {
                allowNull: false,
                type: DataTypes.DATE,
            },
            updatedAt: {
                allowNull: false,
                type: DataTypes.DATE,
            },
        });
    },
    async down(queryInterface) {
        await queryInterface.dropTable('users');
    },
};

问题分析与解决

核心问题出在dbmigrate.js的迁移文件路径配置上,Umzug没有正确找到你的迁移文件,所以只创建了记录迁移状态的sequelizemeta表,却没执行业务表的迁移脚本。

修复方案

1. 修正glob路径格式

当前的glob: '{../migrations/*.js}'写法存在冗余,Umzug的glob配置不需要外层大括号,直接修改为:

const migrator = new Umzug({
    migrations: {
        glob: '../migrations/*.js', // 移除多余的大括号
    },
    // 其他配置保持不变
});

2. 改用绝对路径(更可靠)

相对路径容易受执行环境影响,推荐用path模块生成绝对路径,彻底避免路径解析错误:

const path = require('path'); // 顶部引入path模块

// ... 其他代码

const migrator = new Umzug({
    migrations: {
        glob: path.join(__dirname, '../migrations/*.js'), // 生成绝对路径
    },
    // 其他配置保持不变
});

3. 验证迁移文件检测结果

可以在migrate函数中添加调试代码,确认Umzug是否正确检测到迁移文件:

// 在await migrator.up()之前添加
const migrations = await migrator.list();
console.log('检测到的迁移文件:', migrations);

修改后重新调用initializeData,Umzug就能正确找到并执行迁移脚本,生成对应的业务表。


内容的提问来源于stack exchange,提问作者M4themat1c5

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.09 19:01:17