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

Mongoose报错:Cast to Number failed for value (Object类型) 求助

问题修复:更新用户游戏统计数据时的类型转换错误

错误原因分析

  1. 操作符使用错误:$inc、$max属于MongoDB的顶级更新操作符,不能嵌套在$set中使用。你之前的代码试图通过$set给数字类型字段赋值一个对象(比如{ $max: [...] }),直接触发类型转换失败。
  2. 数据结构设计问题:你的userStats定义为数组类型,但通常单个用户的游戏统计应该是单个对象而非数组。数组结构会导致更新时无法准确定位要修改的统计项,同时增加不必要的复杂度。
  3. 数组字段访问错误:即使保留数组结构,直接使用"userStats.totalGamesPlayed"的写法也无法正确定位数组内的元素,MongoDB不知道要更新数组中的哪一项。

解决方案

方案一:修改数据结构为单个统计对象(推荐)

这是更符合业务逻辑的设计,每个用户对应一组统计数据:

1. 更新userModel.js中的Schema

将userStats从数组改为单个对象:

import mongoose from "mongoose";

const userSchema = mongoose.Schema(
  {
    username: {
      type: String,
      required: [true, "Please add a username"],
    },
    email: {
      type: String,
      required: [true, "Please add your email"],
    },
    password: {
      type: String,
      required: [true, "Please add your password"],
    },
    // 去掉数组括号,改为单个对象
    userStats: {
      totalGamesPlayed: {
        type: Number,
        default: 0,
      },
      highestScore: {
        type: Number,
        default: 0,
      },
    },
  },
  { timestamps: true }
);

const User = mongoose.model("User", userSchema);

export default User;

2. 修正控制器中的更新逻辑

直接使用顶级的$inc和$max操作符,无需嵌套在$set中:

export const updateUserStats = asyncHandler(async (req, res) => {
  const token = req.headers.authorization.split(" ")[1];
  const decoded = jwt.verify(token, process.env.JWT_SECRET);
  
  const user = await User.findById(decoded.id);
  if (!user) {
    return res.status(404).send("User not found");
  }

  const updatedUser = await User.findOneAndUpdate(
    { _id: decoded.id },
    {
      // 直接使用顶级更新操作符
      $inc: { "userStats.totalGamesPlayed": 1 },
      $max: { "userStats.highestScore": req.body.highestScore }
    },
    { new: true } // 返回更新后的文档
  );

  if (updatedUser) {
    res.json(updatedUser);
  } else {
    res.status(400);
    throw new Error("Something went wrong");
  }
});

方案二:保留数组结构(不推荐)

如果因业务需求必须保留userStats为数组,需明确指定要更新的数组元素(假设数组中只有一组统计数据):

const updatedUser = await User.findOneAndUpdate(
  { _id: decoded.id },
  {
    $inc: { "userStats.$.totalGamesPlayed": 1 },
    $max: { "userStats.$.highestScore": req.body.highestScore }
  },
  { new: true }
);

$符号会匹配查询条件中匹配到的第一个数组元素,适用于数组中只有一组统计的场景。


关于save()无法获取更新版本的问题

如果采用方案一的单个对象结构,也可以使用save()方法实现更新,代码如下:

// 替换findOneAndUpdate部分
user.userStats.totalGamesPlayed += 1;
user.userStats.highestScore = Math.max(user.userStats.highestScore, req.body.highestScore);
const updatedUser = await user.save();

之前save()失效大概率是因为数组结构导致的更新定位问题,修改为单个对象后即可正常工作。

内容的提问来源于stack exchange,提问作者Süleyman Eminbəyli

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.02 17:21:06