如何基于键值对合并MongoDB中的JSON对象(关联Review与Launch)
合并MongoDB两个集合的查询结果
现有根据userId查询Review集合的函数:
async function getReviewsByUserId (req, res) { const { userId } = req.params const reviews = await Review.find({ userId }).lean() || [] return res.status(200).send(reviews.reverse()) }
Review集合的文档结构示例:
{ "_id" : ObjectId("1263b55ef2cdd3ebb0654d1dd"), "launchId" : "7fb83b40-7c6f-4099-aaed-fe9d0dc03111", "userId" : "1", } { "_id" : ObjectId("6355565cf5ef2cddebb065584"), "launchId" : "12b53940-136f-3399-aaed-fe9d0dc05473", "userId" : "7fb83b40-7c6f-4099-aaed-fe9d0dc03112", }
需要将每个Review文档中的launchId与Launch集合中对应的文档关联,把Launch数据合并到对应的Review对象里。Launch集合文档示例:
{ "_id" : "12b53940-136f-3399-aaed-fe9d0dc05473", "name" : "The Park", }
期望最终输出结构:
{ "_id" : ObjectId("1263b55ef2cdd3ebb0654d1dd"), "launchId" : "7fb83b40-7c6f-4099-aaed-fe9d0dc03111", "userId" : "1", } { "_id" : ObjectId("6355565cf5ef2cddebb065584"), "launchId" : "12b53940-136f-3399-aaed-fe9d0dc05473", "userId" : "7fb83b40-7c6f-4099-aaed-fe9d0dc03112", "launch": { "_id" : "12b53940-136f-3399-aaed-fe9d0dc05473", "name" : "The Park", } }
方案一:MongoDB聚合查询(推荐,性能更优)
直接在数据库层面完成关联,减少内存处理和数据库请求次数:
async function getReviewsByUserId(req, res) { const { userId } = req.params; const reviews = await Review.aggregate([ // 筛选指定userId的评论 { $match: { userId } }, // 关联Launch集合,通过launchId匹配Launch的_id { $lookup: { from: "launches", // 替换为你的Launch集合实际名称 localField: "launchId", foreignField: "_id", as: "launch" } }, // 将launch数组转为单个对象,保留无对应Launch的评论 { $unwind: { path: "$launch", preserveNullAndEmptyArrays: true } }, // 替代reverse(),直接在数据库层面倒序排序 { $sort: { _id: -1 } } ]); return res.status(200).send(reviews); }
方案二:代码层面合并(适合简单场景)
先批量查询数据,再在内存中完成合并:
async function getReviewsByUserId(req, res) { const { userId } = req.params; // 查询指定userId的评论 const reviews = await Review.find({ userId }).lean() || []; if (!reviews.length) return res.status(200).send([]); // 提取所有去重的launchId,批量查询对应Launch const launchIds = [...new Set(reviews.map(r => r.launchId))]; const launches = await Launch.find({ _id: { $in: launchIds } }).lean() || []; // 将Launch转为以_id为键的映射表,提升查找效率 const launchMap = launches.reduce((map, launch) => { map[launch._id] = launch; return map; }, {}); // 合并数据到对应Review中 const mergedReviews = reviews.map(review => ({ ...review, launch: launchMap[review.launchId] || undefined })); return res.status(200).send(mergedReviews.reverse()); }
内容的提问来源于stack exchange,提问作者mcool
相关产品推荐
相关产品推荐

