Node.js中Mongoose查询如何自定义返回字段与populate结果格式
问题说明
你当前使用Mongoose编写的房间消息查询代码,返回的author字段是包含_id和username的完整对象,但你需要直接把author值设为用户名字符串,同时去掉返回结果里多余的顶层_id字段。
你当前的查询代码:
await Room .findOne({ _id: id_room }) .populate('messages.author','username') .select('messages.message') .then((rooms =>{ return res.status(200).json({ rooms }); })).catch((error)=>{ return res.status(500).json({ message:error.message,error }); });
当前返回结构:
{ "rooms": { "_id": "62c6e2f552d6718f6aea01f4", "messages": [ { "message": "hi", "author": { "_id": "62c6d43d6c5c2aebdc575019", "username": "vadim" } }, { "message": "hi", "author": { "_id": "62c7faf8ef9176ea1b6dbd57", "username": "oleg" } } ] } }
目标返回结构:
{ "rooms": { "messages": [ { "message": "hi", "author": "vadim" }, { "message": "hi", "author": "oleg" } ] } }
你尝试过去掉populate直接用.select('messages.message message.author'),但这种写法只会返回作者的ObjectId,拿不到用户名。
解决方案
有两种常用实现方式,按需选择即可:
方案1:查询后对返回结果做格式转换(最直观,不需要改Schema配置)
拿到populate后的查询结果后,手动遍历messages数组,把author对象替换成其中的username字段,同时删掉不需要的顶层_id即可,修改后的代码如下:
await Room .findOne({ _id: id_room }) .populate('messages.author', 'username') .select('messages') // 只返回messages字段,自动排除顶层_id .then(room => { // 遍历消息格式化author字段 const formattedMessages = room.messages.map(msg => { return { message: msg.message, author: msg.author.username // 直接取populate后的username值 } }) return res.status(200).json({ rooms: { messages: formattedMessages } }); }).catch(error => { return res.status(500).json({ message: error.message, error }); });
方案2:使用Mongoose聚合管道直接查询出目标结构(不需要后端二次处理数据)
如果不想拿到数据后再手动遍历转换,可以直接用MongoDB的聚合语法,在查询阶段就完成字段格式调整,示例代码:
await Room.aggregate([ // 匹配对应id的房间 { $match: { _id: new mongoose.Types.ObjectId(id_room) } }, // 关联用户集合,替换messages.author { $lookup: { from: 'users', // 替换成你实际存储用户的集合名 localField: 'messages.author', foreignField: '_id', as: 'authorDetails' } }, // 重构messages字段格式 { $addFields: { messages: { $map: { input: '$messages', as: 'msg', in: { message: '$$msg.message', author: { $getField: { field: 'username', input: { $arrayElemAt: [ '$authorDetails', { $indexOfArray: ['$authorDetails._id', '$$msg.author'] } ] } } } } } } } }, // 只保留messages字段,去掉多余字段 { $project: { messages: 1, _id: 0 } } ]).then(roomResult => { return res.status(200).json({ rooms: roomResult[0] }) }).catch(error => { return res.status(500).json({ message: error.message, error }) })
注意:聚合查询里匹配
_id时,需要手动把字符串id转成MongoDB的ObjectId类型,否则会匹配不到数据。
内容的提问来源于stack exchange,提问作者qwerty
相关产品推荐
相关产品推荐

