如何在两层map函数中使用await从MongoDB获取分类文档并修改API返回结果
问题分析与解决方法
你的代码返回undefined数组主要有两个核心问题:
- 外层
map没有返回值:你在外层的searchResults.map里没有返回任何异步操作的结果,所以Promise.all接收的是一堆undefined的Promise,最终结果自然是全undefined的数组。 - 内层
map的Promise未被等待:内层的item.categories.map返回的是Promise数组,但你没有用Promise.all去等待这些Promise全部完成,就算外层有返回,也只是返回一堆未resolved的Promise对象,而不是实际的分类数据。
修正后的代码
const resultArray = await Promise.all( searchResults.map(async (item) => { // 等待所有分类ID对应的查询完成,注意这里用findOne更合适(因为ID唯一) const categoryDocs = await Promise.all( item.categories.map(async (categoryId) => { const doc = await CategoryType.findOne({ _id: categoryId }); // 只提取我们需要的_id和name字段 return { _id: doc._id, name: doc.name }; }) ); // 返回修改了categories字段的新对象(避免修改原item) return { ...item, categories: categoryDocs }; }) );
关键细节说明
- 用
Promise.all包裹内层的map结果,确保所有分类查询都完成后再继续处理。 - 把
CategoryType.find改成CategoryType.findOne:因为你是根据唯一的_id查询单个分类文档,find会返回数组,而findOne直接返回单个文档对象,更符合需求。 - 返回一个新的对象(用展开运算符
...item)而不是直接修改原item,这是更安全的做法,避免意外修改原数据。 - 明确提取
_id和name字段,确保返回的结构完全符合你的期望,不会包含分类文档中的其他冗余字段。
额外优化建议
如果你的数据集比较大,这种逐个查询分类的方式会产生大量数据库请求,可能影响性能。可以考虑先收集所有需要查询的分类ID,一次性批量查询,再映射到对应的结果中:
// 收集所有需要查询的分类ID,去重避免重复查询 const allCategoryIds = [...new Set(searchResults.flatMap(item => item.categories))]; // 批量查询所有分类 const categoryMap = new Map( (await CategoryType.find({ _id: { $in: allCategoryIds } })).map(doc => [doc._id.toString(), { _id: doc._id, name: doc.name }]) ); // 映射结果 const resultArray = searchResults.map(item => ({ ...item, categories: item.categories.map(id => categoryMap.get(id.toString())) }));
这种方式只需要1次数据库查询,性能会好很多,尤其是在数据量较大的场景下。
内容的提问来源于stack exchange,提问作者Andrea D_
相关产品推荐
相关产品推荐

