MongoDB中空对象Object.keys返回异常长度值及空对象校验方法咨询
嘿,我之前也碰到过类似的Mongoose/MongoDB对象处理坑,咱们一步步来搞清楚问题出在哪,以及怎么解决。
首先,先解释你遇到的奇怪现象:为什么打印是{}但Object.keys和Object.values结果不对?这大概率是因为你用了Mongoose(从Schema定义和行为来看很可能)。Mongoose的默认行为是,当Schema里定义了嵌套对象(比如你的childLimit),即使创建文档时没传这个字段,它也会把这个字段初始化为一个空的Mongoose子文档对象——这个对象不是纯JS空对象,而是带有Mongoose内部的隐藏属性(比如用于跟踪变更的标识、版本字段等),这些属性会被Object.keys和Object.values检测到,所以才会出现长度为2、值包含true和undefined的奇怪结果。
接下来分两部分解决你的问题:
一、正确判断childLimit字段是否存在
这里要分两种场景:
如果用原始MongoDB驱动
直接检查字段是否为undefined或者用in操作符:
// doc是MongoDB驱动返回的纯JS文档 if (doc.childLimit !== undefined) { console.log("childLimit字段存在"); } else { console.log("childLimit字段不存在"); } // 或者用in操作符,更严谨(避免字段值为undefined的情况) if ('childLimit' in doc) { // 字段存在 }
如果用Mongoose
因为Mongoose会自动填充空对象,所以直接检查实例属性会不准确,最好先把Mongoose文档转换成纯JS对象(POJO):
// userDoc是Mongoose查询返回的文档实例 const plainUser = userDoc.toObject(); // 或者toJSON(),效果类似 if ('childLimit' in plainUser) { console.log("childLimit字段存在"); } else { console.log("childLimit字段不存在"); }
另外,也可以在查询阶段就用MongoDB的$exists操作符筛选,提前过滤出符合条件的文档:
// 查询存在childLimit字段的用户 db.users.find({ childLimit: { $exists: true } }); // 查询不存在childLimit字段的用户 db.users.find({ childLimit: { $exists: false } });
二、正确判断childLimit对象是否为空
同样,核心是先摆脱Mongoose的包装,拿到纯JS对象,再进行判断:
方法1:转成POJO后用Object.keys
const plainUser = userDoc.toObject(); if ('childLimit' in plainUser) { const isEmpty = Object.keys(plainUser.childLimit).length === 0; if (isEmpty) { console.log("childLimit存在但为空对象"); } else { console.log("childLimit有有效数据"); } }
方法2:自定义空对象判断函数
如果不想转POJO,也可以写一个忽略继承属性的判断函数,避免Mongoose内部属性干扰:
function isEmptyObject(obj) { for (const key in obj) { // 只检查对象自身的可枚举属性 if (Object.prototype.hasOwnProperty.call(obj, key)) { return false; } } return true; } // 直接用在Mongoose子文档上 if (isEmptyObject(userDoc.childLimit)) { console.log("childLimit为空"); }
方法3:从根源避免空对象生成
如果你根本不想让Mongoose自动生成空的childLimit对象,可以修改Schema,给childLimit设置default: undefined:
const userSchema = new mongoose.Schema({ name: { type: String }, childLimit: { type: { dailyLimit: { type: Number } }, default: undefined // 关键:没传值时不生成空对象,数据库里直接无此字段 } });
这样修改后,创建用户时如果没传childLimit,数据库里就不会有这个字段,查询返回的文档里childLimit就是undefined,判断起来会简单很多。
内容的提问来源于stack exchange,提问作者Taimoor Hussain Musa

