JavaScript中Mongoose返回对象检测键值异常的原因咨询
hasOwnProperty检测键会返回false? 这问题我之前排查过好几次!核心原因是你通过mongoose.find().exec()拿到的不是普通的JavaScript对象,而是Mongoose Document实例——这是Mongoose为了实现ORM功能封装的特殊对象,和你写的字面量对象完全不是一回事。
逐个拆解你的测试现象:
obj.hasOwnProperty('available_count')返回false
Mongoose Document的字段并不是直接挂载在对象自身上的,而是通过原型链的getter/setter来代理访问的。这些数据库返回的实际数据存在Document内部的_doc属性里,而hasOwnProperty只能检测对象自身可枚举的属性,自然找不到available_count。_.isObject()返回true
lodash的_.isObject()只要是引用类型(除了null)都会返回true,Document本身确实是JS对象实例,所以这个检测结果是对的,但它没法区分普通对象和Mongoose封装的特殊实例。JSON.parse(JSON.stringify(obj))能解决问题
当你用JSON.stringify序列化Document时,Mongoose会自动调用它内置的toJSON()方法,把_doc里的原始数据转成标准JSON格式。解析后得到的就是纯普通JS对象,这时hasOwnProperty就能正常检测自身属性了。
更优雅的解决方案(不用序列化绕弯):
查询时直接返回普通对象:用
lean()
在查询链中加上.lean(),Mongoose会跳过Document实例的创建,直接返回原始的JS对象,性能也更好:Model.find().lean().exec((err, docs) => { if (err) throw err; docs.forEach(doc => { console.log(doc.hasOwnProperty('available_count')); // 现在返回true }); });把已有的Document转成普通对象:用
toObject()
如果已经拿到了Document实例,可以调用它的toObject()方法直接转成普通对象:Model.findById('5af1c07d5542fc9307847a6a').exec((err, doc) => { if (err) throw err; const plainObj = doc.toObject(); console.log(plainObj.hasOwnProperty('available_count')); // true });
内容的提问来源于stack exchange,提问作者made_in_india

