Node.js中Mongoose返回对象无法修改属性的原因及解决方法
问题原因
Mongoose执行save()、find()等操作返回的结果默认是Mongoose Document类实例,不是普通JavaScript对象,这类实例的属性读写完全受对应Schema的规则约束:
- 你的
Excercise模型中username字段被定义为mongoose.Schema.Types.ObjectId类型,Mongoose会对该字段的所有赋值操作做类型校验和强制转换 - 你尝试给
username赋值的name.username是字符串类型,不符合ObjectId的类型要求,赋值操作会被Mongoose静默拦截,字段最终保留原来存储的ObjectId值 - 额外代码问题:路由定义的路径参数是
:userId,你创建练习记录时取用户ID的写法req.body[':_id']是错误的,应该从req.params.userId获取
解决方案
有两种常用的修复方式,按需选择即可:
方案1:将Mongoose文档转为普通JS对象后修改
调用文档实例的.toObject()方法,把Mongoose文档转换成不受Schema约束的普通JS对象,之后再修改属性就会正常生效:
app.post('/api/users/:userId/exercises',(req,res)=>{ const newEx = new Excercise({ username : req.params.userId, // 修正参数获取逻辑 description : req.body.description, duration : Number(req.body.duration), // 做类型转换避免不匹配 date : req.body.date ? new Date(req.body.date) : undefined, }) newEx.save().then((data)=>{ // 转成普通JS对象 const resData = data.toObject(); User.findOne({_id:resData.username}).lean().exec().then((user)=>{ resData.username = user.username; return res.json(resData) }) }).catch(err=>res.status(400).json({error: err.message})) })
方案2:使用Mongoose的populate实现关联查询
不需要手动查询User表再修改属性,直接在查询练习记录时用populate关联User表,把username字段替换成关联的用户文档内容,写法更简洁:
app.post('/api/users/:userId/exercises',(req,res)=>{ const newEx = new Excercise({ username : req.params.userId, description : req.body.description, duration : Number(req.body.duration), date : req.body.date ? new Date(req.body.date) : undefined, }) newEx.save().then((data)=>{ // 关联查询User表,只取需要的username字段 Excercise.findById(data._id) .populate('username', 'username -_id') .lean() // 直接返回普通JS对象 .then(resData=>res.json(resData)) }).catch(err=>res.status(400).json({error: err.message})) })
注意:如果用populate方案,默认返回的字段结构会是
username: {username: "实际用户名"},如果需要直接返回字符串格式的username,在拿到结果后做一次字段扁平化处理即可。
内容的提问来源于stack exchange,提问作者Suhail Kv
相关产品推荐
相关产品推荐

