使用Mongoose填充子文档时出现非期望结构的问题
当然可以!用Mongoose原生就能实现,不用手动转换数据
我给你两种靠谱的方案,你可以根据自己的场景选择:
方案一:使用聚合管道(推荐,完全原生无手动转换)
聚合管道能帮你直接在数据库层面完成数据的重组和关联,完美匹配你的需求:
const mongoose = require('mongoose'); const user = await User.aggregate([ // 定位目标用户 { $match: { _id: mongoose.Types.ObjectId(req.user.id) } }, // 展开projects数组,方便后续关联操作 { $unwind: "$projects" }, // 关联Project集合,拉取项目名称 { $lookup: { from: "projects", // 这里填你的Project集合的实际名称 localField: "projects._id", foreignField: "_id", as: "projectInfo" } }, // 展开关联后的projectInfo数组 { $unwind: "$projectInfo" }, // 重组项目结构,把字段平级整合 { $addFields: { "projects.name": "$projectInfo.name", "projects._id": "$projectInfo._id" } }, // 清理不需要的冗余字段 { $project: { projectInfo: 0 } }, // 把处理后的项目重新组合成数组 { $group: { _id: "$_id", projects: { $push: "$projects" } } } ]);
执行后返回的user[0].projects结构就是你想要的:
[ { name: 'ProjectName', _id: 5a50ccde03c2d1f5a07e0ff3, selectedLanguage: 'en' } ]
方案二:借助Populate的Transform钩子
如果你更习惯用findById + populate的写法,可以通过Mongoose的transform选项配合查询后处理来调整结构:
const user = await User.findById(req.user.id, 'projects') .populate({ path: 'projects._id', select: 'name', // 自定义填充后的数据结构 transform: (doc, ret) => ({ _id: ret._id, name: ret.name }) }) .lean() // 转成普通JS对象方便整合 .then(doc => { // 整合填充结果和自定义字段 doc.projects = doc.projects.map(item => ({ ...item._id, selectedLanguage: item.selectedLanguage })); return doc; });
这种方式也能得到期望的结构,属于基于Mongoose原生API的轻量处理。
额外小提示:
你Schema里projects._id的unique: true设置是无效的——Mongoose无法保证数组内的元素唯一。如果要避免用户重复添加同一个项目,建议用$addToSet操作符来添加项目,或者在业务逻辑里先做重复检查。
内容的提问来源于stack exchange,提问作者nanobar
相关产品推荐
相关产品推荐

