Mongoose查询populate关联User时如何将多个关联字段扁平化处理
你可以通过以下3种常用方案实现目标结构:
方案1:查询后手动映射转换
最灵活的实现方式,不需要修改原有查询逻辑,拿到结果后遍历处理即可,适合临时转换的场景:
// 查询时加lean()将mongoose文档转为普通JS对象,提升处理性能 const datapoints = await Datapoint.find({}) .populate([{path:'player',select:['team']}]) .lean(); // 遍历格式化每个结果 const formattedDatapoints = datapoints.map(item => { // 存在player为空的场景可先加非空判断避免报错 const { player, ...rest } = item; return { ...rest, player: player._id, 'player.team': player.team } });
如果你没有加lean(),也可以对每个mongoose文档调用toObject()方法转为普通对象后再处理。
方案2:聚合管道查询阶段直接生成目标结构
不需要二次处理查询结果,适合数据量较大的场景,性能更高:
const formattedDatapoints = await Datapoint.aggregate([ // 关联User表,替代原有的populate逻辑 { $lookup: { from: 'users', // 此处为MongoDB中User对应的集合名,默认是模型名小写加s,自定义过集合名请替换 localField: 'player', foreignField: '_id', as: 'playerInfo' } }, // 将lookup返回的数组转为单个对象 { $unwind: '$playerInfo' }, // 投影生成你需要的扁平化结构 { $project: { type: 1, value: 1, recorder: 1, date: 1, __v: 1, player: 1, 'player.team': '$playerInfo.team' } } ])
方案3:Schema全局钩子自动转换
适合所有Datapoint查询都需要返回该格式的场景,配置后不需要每次查询单独写处理逻辑:
// 在定义dataPointSchema的代码后新增这段配置 dataPointSchema.set('toJSON', { transform: function(doc, ret) { // 仅当player是已关联的对象时做转换 if (ret.player && typeof ret.player === 'object') { const team = ret.player.team; ret.player = ret.player._id; ret['player.team'] = team; } return ret; } }); // 之后正常查询,接口返回调用res.json()时会自动做格式转换 const datapoints = await Datapoint.find({}).populate([{path:'player',select:['team']}]);
内容的提问来源于stack exchange,提问作者David
相关产品推荐
相关产品推荐

