使用Sequelize+MySQL+Node.js实现一对多关联时遇未处理Promise拒绝错误
Sequelize一对多关联配置错误排查与解决
问题概述
使用Sequelize、MySQL和Node-Express搭建产品(Product)与评论(Review)的一对多关联时,出现未处理的Promise拒绝错误,移除关联配置代码后项目恢复正常,需排查关联配置中的问题。
错误日志
server is running on port : 8080 Executing (default): SELECT 1+1 AS result Executing (default): SELECT TABLE_NAME FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_TYPE = 'BASE TABLE' AND TABLE_NAME = 'products' AND TABLE_SCHEMA = 'node_sequelize_api_db' connected to db Executing (default): CREATE TABLE IF NOT EXISTS `products` (`id` INTEGER NOT NULL auto_increment , `title` VARCHAR(255) NOT NULL, `price` INTEGER, `description` TEXT, `published` TINYINT(1), `createdAt` DATETIME NOT NULL, `updatedAt` DATETIME NOT NULL, PRIMARY KEY (`id`)) ENGINE=InnoDB; Executing (default): SHOW INDEX FROM `products` Executing (default): SELECT TABLE_NAME FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_TYPE = 'BASE TABLE' AND TABLE_NAME = 'reviews' AND TABLE_SCHEMA = 'node_sequelize_api_db' Executing (default): CREATE TABLE IF NOT EXISTS `reviews` (`id` INTEGER NOT NULL auto_increment , `rating` INTEGER, `description` TEXT, `createdAt` DATETIME NOT NULL, `updatedAt` DATETIME NOT NULL, `productId` INTEGER, PRIMARY KEY (`id`), FOREIGN KEY (`productId`) REFERENCES `products` (`id`) ON DELETE SET NULL ON UPDATE CASCADE) ENGINE=InnoDB; (node:15924) UnhandledPromiseRejectionWarning: Error at Query.run (/home/grace/Desktop/_SOFTWARE_ENGINEER/FULLSTACK/node_sequelize/node_modules/sequelize/lib/dialects/mysql/query.js:52:25) at retry (/home/grace/Desktop/_SOFTWARE_ENGINEER/FULLSTACK/node_sequelize/node_modules/sequelize/lib/sequelize.js:314:28) at process._tickCallback (internal/process/next_tick.js:68:7) (node:15924) UnhandledPromiseRejectionWarning: Unhandled promise rejection. This error originated either by throwing inside of an async function without a catch block, or by rejecting a promise which was not handled with .catch(). (rejection id: 1) (node:15924) [DEP0018] DeprecationWarning: Unhandled promise rejections are deprecated. In the future, promise rejections that are not handled will terminate the Node.js process with a non-zero exit code.
相关代码
Model/index.js
require('dotenv').config(); const {Sequelize, DataTypes} = require('sequelize') const sequelize = new Sequelize( process.env.DB, process.env.USER, process.env.PASSWORD,{ host:process.env.HOST, dialect: process.env.DIALECT, operatorsAlias: false, /*pool:{ max: dbConfig.pool.max, min: dbConfig.pool.min, acquire: dbConfig.pool.acquire, idle: dbConfig.pool.idle }*/ } ) sequelize.authenticate() .then(() =>{ console.log('connected to db') }) .catch(err =>{ console.log('Error' + err) }) const db = {} db.Sequelize = Sequelize db.sequelize = sequelize db.products = require('./productModel.js')(sequelize, DataTypes); db.reviews = require('./reviewModel.js')(sequelize, DataTypes); //it won't create the table over and over db.sequelize.sync({force: false}) .then(()=>{ console.log('yes re-sync done!') }) //implement One-to-Many relationship db.products.hasMany(db.reviews,{ foreignKey: 'product_id', as: 'review', }) db.reviews.belongsTo(db.products,{ foreignKey: 'product_id', as: 'product' })
ProductModel.js
module.exports = (sequelize, DataTypes) => { return sequelize.define("product", { title: { type: DataTypes.STRING, allowNull: false }, price: { type: DataTypes.INTEGER }, description: { type: DataTypes.TEXT }, published: { type: DataTypes.BOOLEAN } }) }
ReviewModel.js
module.exports = (sequelize, DataTypes) => { return sequelize.define("review", { rating: { type: DataTypes.INTEGER, }, description: { type: DataTypes.TEXT } }) }
产品控制器关联查询代码
//7. connect 1 to many relation Roduct to Review const getProductReviews = async (req, res) =>{ try{ const data = await Product.findAll({include: Review}) }catch(e){ console.error(e) } } module.exports ={ addProduct, getAllProducts, getOneProduct, updateProduct, deleteProduct, getPublishedProduct, getProductReviews }
问题分析
错误根源在于以下几点:
- 关联配置时机错误:关联定义放在了
sequelize.sync()之后,导致Sequelize执行表同步时未读取到关联规则,无法正确生成匹配的外键约束。 - 外键名称不匹配:关联配置中指定外键为
product_id,但Sequelize默认使用驼峰式命名创建了productId字段,两者不一致引发外键约束错误。 - 未处理Promise拒绝:
sequelize.sync()未添加catch处理,导致同步过程中的错误触发未处理的Promise警告。 - 关联查询配置错误:
include直接使用Review模型,未匹配关联定义中的as别名,且未返回响应给客户端。
解决方案
1. 调整关联配置位置
将关联定义移至sequelize.sync()之前,确保同步表时应用关联规则:
const db = {} db.Sequelize = Sequelize db.sequelize = sequelize db.products = require('./productModel.js')(sequelize, DataTypes); db.reviews = require('./reviewModel.js')(sequelize, DataTypes); // 先定义一对多关联 db.products.hasMany(db.reviews,{ foreignKey: 'productId', // 匹配默认驼峰式字段名 as: 'reviews', // 使用复数别名更符合语义 }) db.reviews.belongsTo(db.products,{ foreignKey: 'productId', as: 'product' }) // 再执行表同步 db.sequelize.sync({force: false}) .then(()=>{ console.log('yes re-sync done!') }) .catch(err => { console.error('Sync failed:', err) // 添加错误捕获 })
2. 统一外键命名(可选)
若偏好下划线命名风格,需在模型中启用underscored: true,让Sequelize自动生成下划线格式的字段和外键:
ProductModel.js 修改
module.exports = (sequelize, DataTypes) => { return sequelize.define("product", { title: { type: DataTypes.STRING, allowNull: false }, price: { type: DataTypes.INTEGER }, description: { type: DataTypes.TEXT }, published: { type: DataTypes.BOOLEAN } }, { underscored: true // 启用下划线命名规则 }) }
ReviewModel.js 修改
module.exports = (sequelize, DataTypes) => { return sequelize.define("review", { rating: { type: DataTypes.INTEGER, }, description: { type: DataTypes.TEXT } }, { underscored: true }) }
此时关联配置中的foreignKey: 'product_id'即可与数据库字段匹配。
3. 修正关联查询代码
使用关联定义的as别名,并补充响应逻辑:
const getProductReviews = async (req, res) =>{ try{ const data = await Product.findAll({ include: [{ model: Review, as: 'reviews' // 与关联配置中的别名一致 }] }) res.status(200).json(data) // 返回查询结果 }catch(e){ console.error(e) res.status(500).json({error: 'Failed to fetch product reviews', details: e.message}) // 返回错误响应 } }
验证
完成上述修改后,重新启动项目,Sequelize将正确创建带匹配外键的表结构,关联查询可正常获取产品及其对应的评论列表,且不会再出现未处理的Promise拒绝警告。
内容的提问来源于stack exchange,提问作者kalombo grace
相关产品推荐
相关产品推荐

