Mongoose findById返回对象遍历问题:无法取值及解决方法
Mongoose查询结果遍历问题解答
嘿,我来帮你捋清楚这个问题——你遇到的坑其实是Mongoose返回的对象和普通JS对象的区别导致的,咱们一步步来解决:
为什么原代码拿不到预期值?
你用Object.keys(result).forEach(...)没拿到想要的内容,核心原因是:Mongoose查询返回的不是原生JavaScript对象,而是它自己封装的Document实例。
这个实例看起来和普通对象结构一样,但它内部藏了很多Mongoose的内置方法(比如save()、update())和属性,Object.keys()只能拿到这些可枚举的内置属性,而你真正需要的业务数据其实存在它的_doc属性里,直接遍历根本碰不到。你可以试试打印Object.keys(result),会看到一堆和业务无关的Mongoose内置键,这就是问题所在。
解决步骤:先转成普通对象,再递归遍历嵌套结构
第一步:把Mongoose文档转成原生JS对象
有两种简单的方式:
- 查询时直接返回普通对象:在查询语句末尾加
lean(),这样Mongoose就不会返回Document实例,直接给你原生对象:// 示例查询代码 YourModel.findOne({ /* 你的查询条件 */ }) .lean() .exec((err, result) => { // 这里的result就是普通JS对象了 }); - 已拿到Document实例时转换:如果已经获取了result,用
toObject()方法把它转成普通对象:const plainResult = result.toObject();
第二步:递归遍历处理嵌套对象和数组
因为你的结果里有嵌套对象(owner)、数组(members、admins),普通的单层遍历只能拿到第一层键,所以需要写一个递归函数来遍历所有层级的键值对。
原生JS兼容写法(ES5可用)
function traverseAllKeys(obj, parentKey = '') { // 先处理数组:遍历每个元素 if (Array.isArray(obj)) { obj.forEach((item, index) => { const currentKey = parentKey ? `${parentKey}[${index}]` : `[${index}]`; traverseAllKeys(item, currentKey); }); return; } // 处理对象:遍历每个键 if (typeof obj === 'object' && obj !== null) { Object.keys(obj).forEach(key => { const currentKey = parentKey ? `${parentKey}.${key}` : key; const value = obj[key]; // 如果值是对象/数组,继续递归;否则直接输出键值 if (typeof value === 'object' && value !== null) { traverseAllKeys(value, currentKey); } else { console.log(`键:${currentKey},值:${value}`); } }); } else { // 非对象非数组的直接输出 console.log(`键:${parentKey},值:${obj}`); } } // 使用示例 const plainResult = result.toObject(); // 或者用lean()拿到的对象 traverseAllKeys(plainResult);
ES6+简洁写法
如果你可以用ES6及以上的特性,用箭头函数和Object.entries()会更清爽:
const traverseAllKeys = (obj, parentKey = '') => { if (Array.isArray(obj)) { obj.forEach((item, idx) => traverseAllKeys(item, `${parentKey}[${idx}]`)); return; } if (typeof obj === 'object' && obj !== null) { for (const [key, value] of Object.entries(obj)) { const currentKey = parentKey ? `${parentKey}.${key}` : key; traverseAllKeys(value, currentKey); } } else { console.log(`键:${parentKey},值:${obj}`); } }; // 使用 traverseAllKeys(result.toObject());
测试你的示例数据
用你给出的结果(转成普通对象后)运行上面的函数,会输出:
键:owner.fullName,值:xxx 键:owner.userName,值:xxx 键:members[0].userName,值:xxx 键:members[0].fullName,值:xxx 键:members[0].position,值: 键:admins[0],值:xxx 键:admins[1],值:ashg 键:_id,值:5a482302a469a068edc004e3 键:type,值:xxxx 键:name,值:xxxx xxxx 键:descrip,值:xxxx 键:startDate,值:2018-01-01 键:endDate,值:
这样就能完整遍历所有嵌套的键值对啦!
内容的提问来源于stack exchange,提问作者mo_maat
相关产品推荐
相关产品推荐

