Mongoose查询问题:用户数组ID关联文档返回undefined
问题:筛选带非空Artikel数组的用户并关联查询时返回undefined
我有一个User模型,其中eingestellteArtikel数组存储的是Artikel模型的文档ID。现在需要筛选出该数组不为空的所有用户,同时通过这些ID读取对应的Artikel文档,但控制台输出liste时显示undefined。
相关代码
export const AlleUserMitArtikel = async (req, res) => { try { const alleUser = await User.find({ eingestellteArtikel: { $exists: true, $not: { $size: 0 } }, }); const liste = await Promise.all( alleUser.map(async (user) => { console.log(user); //控制台显示正确对象 user.eingestellteArtikel.map(async (id) => { console.log(id); //控制台显示正确ID return await Artikel.find({ _id: id }); }); }) ); console.log(liste); //显示undefined res.status(200).json(alleUser); } catch (error) { console.log(error); } };
User模型结构
{ _id: new ObjectId("630f36f0295ec768e2072c10"), eingestellteArtikel: [ '630fe7caabfdf4387030a723', '63105cbedae68f22984ba434' ], createdAt: 2022-08-31T10:24:48.845Z, updatedAt: 2022-09-01T07:18:22.044Z, __v: 0, }
错误输出
630fe7caabfdf4387030a723 63105cbedae68f22984ba434 [ undefined, undefined ]
原因分析
- 外层map无返回值:
alleUser.map(async (user) => { ... })内部没有返回任何内容,导致Promise.all接收的是一组undefined,最终liste就是[undefined, ...]。 - 内层异步未处理:内层的
user.eingestellteArtikel.map(async (id) => { ... })生成了异步Promise数组,但既没有用Promise.all等待这些异步操作完成,也没有将这个数组返回给外层map。
解决方法
方法1:修复原异步逻辑
手动处理内层的异步Promise数组,并确保外层map返回处理后的结果:
export const AlleUserMitArtikel = async (req, res) => { try { const alleUser = await User.find({ eingestellteArtikel: { $exists: true, $not: { $size: 0 } }, }); const liste = await Promise.all( alleUser.map(async (user) => { // 用Promise.all等待所有Artikel查询完成 const artikelList = await Promise.all( user.eingestellteArtikel.map(id => Artikel.findById(id)) // findById比find({_id:id})更高效 ); // 返回包含用户信息和对应Artikel的对象 return { ...user.toObject(), // 转换为普通对象避免Mongoose文档的限制 eingestellteArtikel: artikelList }; }) ); console.log(liste); // 现在会正确输出用户及对应Artikel数组 res.status(200).json(liste); } catch (error) { console.log(error); res.status(500).json({ error: error.message }); } };
方法2:使用Mongoose的populate(更优)
Mongoose支持直接在查询时关联其他模型,避免循环查询带来的性能问题:
export const AlleUserMitArtikel = async (req, res) => { try { // 查询用户时直接关联Artikel模型,自动替换ID为对应文档 const alleUserMitArtikel = await User.find({ eingestellteArtikel: { $exists: true, $not: { $size: 0 } }, }).populate('eingestellteArtikel'); // 字段名需与User模型定义一致 console.log(alleUserMitArtikel); // 每个user的eingestellteArtikel已转为Artikel文档 res.status(200).json(alleUserMitArtikel); } catch (error) { console.log(error); res.status(500).json({ error: error.message }); } };
为什么选populate?
- 减少数据库查询次数:原逻辑是N+1次查询(N为用户数量),populate仅需2次查询(一次查用户,一次批量查所有关联的Artikel),性能更优。
- 代码更简洁,无需手动处理异步循环。
内容的提问来源于stack exchange,提问作者Captai-N
相关产品推荐
相关产品推荐

