无法选中指定Game对象?分数增加功能抛出异常问题排查
问题排查与解决方案
核心问题分析
findOne参数传递错误
Sequelize的findOne仅接受单个配置对象,你当前将查询条件、排序/分页参数拆分为两个独立对象传入,导致排序和limit设置完全不生效,无法定位到用户最新的Game记录。同时如果用户无对应游戏记录,game会返回null,后续执行game.score += 1会直接抛出Cannot read properties of null异常。Game模型缺少
createdAt字段
你的SQL逻辑依赖createdAt排序,但当前Game模型未定义该字段,也未开启Sequelize自动时间戳功能,数据库表中不存在该字段,排序操作会触发SQL语法错误。
修复步骤
1. 修正findOne调用逻辑
合并所有查询选项到单个对象,并增加空值判断避免空指针异常:
exports.increaseScore = async (req, res) => { const userId = res.userId; try { // 将where、order、limit合并到同一配置对象 const game = await Game.findOne({ where: { userId: userId }, limit: 1, order: [['createdAt', 'DESC']] }); // 无对应记录时直接返回提示 if (!game) { return res.status(404).json("未找到该用户的游戏记录"); } game.score += 1; await game.save(); res.status(200).json("分数增加成功!"); } catch (err) { res.status(400).json(err.message || "操作失败"); } };
2. 完善Game模型的时间戳配置
两种可选方案:
方案一:开启自动时间戳(推荐)
让Sequelize自动生成createdAt和updatedAt字段:
const Game = sequelize.define("Games", { id: { type: Sequelize.INTEGER, autoIncrement: true, primaryKey: true, unique: true, }, score: { type: Sequelize.INTEGER, allowNull: false }, difficulty: { type: Sequelize.INTEGER, allowNull: false }, }, { timestamps: true, freezeTableName: true // 保持表名为Games,不自动复数化 }); exports.Game = Game;
方案二:手动定义createdAt字段
若不需要自动时间戳,手动添加字段定义:
const Game = sequelize.define("Games", { id: { type: Sequelize.INTEGER, autoIncrement: true, primaryKey: true, unique: true, }, score: { type: Sequelize.INTEGER, allowNull: false }, difficulty: { type: Sequelize.INTEGER, allowNull: false }, createdAt: { type: Sequelize.DATE, allowNull: false, defaultValue: Sequelize.NOW } }); exports.Game = Game;
3. 更新数据库表结构(开发环境)
执行模型同步更新表结构(生产环境建议用迁移脚本):
// 在关联关系定义后执行 sequelize.sync({ alter: true });
内容的提问来源于stack exchange,提问作者Gábor Kiss
相关产品推荐
相关产品推荐

