MongoDB/Mongoose关联posts与likes集合:查询时显示用户点赞状态方案
最佳方案:使用MongoDB聚合管道实现
嘿,这个需求用MongoDB的聚合框架来实现是最高效的,完全能替代SQL里的JOIN/子查询逻辑,而且能在数据库端一次性完成所有计算,避免客户端做N+1查询拖慢性能。
核心思路
我们需要把posts和likes集合关联起来,同时只过滤当前用户的点赞记录,最后通过判断是否存在匹配的点赞记录来生成is_liked字段。下面是具体的实现步骤和代码:
Mongoose代码示例
假设当前登录用户的ID是currentUserId(你可以从登录会话或请求中获取这个值):
const currentUserId = 456; // 替换为实际的当前用户ID const posts = await Post.aggregate([ // 1. 先按帖子的timestamp降序排序,满足你要的排序需求 { $sort: { timestamp: -1 } }, // 2. 关联likes集合,仅查询当前用户对该帖子的点赞记录 { $lookup: { from: 'likes', // 关联的集合名 let: { postId: '$_id' }, // 定义一个变量,存储当前帖子的_id pipeline: [ // 子管道:只匹配当前用户对该帖子的点赞 { $match: { $expr: { $and: [ { $eq: ['$post_id', '$$postId'] }, // 帖子ID匹配 { $eq: ['$user_id', currentUserId] } // 当前用户ID匹配 ] } } } ], as: 'user_like' // 把匹配的点赞记录存到这个数组字段里 } }, // 3. 新增is_liked字段:判断user_like数组是否有内容(即是否点赞过) { $addFields: { is_liked: { $gt: [{ $size: '$user_like' }, 0] } } }, // 4. 可选:移除不需要的user_like数组,让返回结果更简洁 { $project: { user_like: 0 // 0表示不返回这个字段 } } ]);
关键细节解释
- $lookup的子管道过滤:这里没有用默认的$lookup全量关联,而是通过
let和pipeline只查询当前用户的点赞记录,这样返回的user_like数组要么是空数组(未点赞),要么只有一个元素(已点赞),避免了返回大量无关数据。 - 性能优化建议:给
likes集合创建复合索引db.likes.createIndex({ user_id: 1, post_id: 1 }),这样$lookup里的匹配查询会快很多,尤其是数据量大的时候。 - 替代方案对比:如果你尝试用Mongoose的
populate,它默认会关联所有匹配的likes记录,没法只过滤当前用户,所以聚合管道是更合适的选择。
返回结果示例
最终返回的每个帖子文档会包含新增的is_liked布尔值,比如:
[ { _id: 1, user_id: 789, title: "我的第一篇帖子", text: "内容...", timestamp: ISODate("2024-05-20T10:00:00Z"), likes: 15, is_liked: true // 当前用户点赞过 }, { _id: 2, user_id: 101, title: "第二篇帖子", text: "内容...", timestamp: ISODate("2024-05-19T14:30:00Z"), likes: 8, is_liked: false // 当前用户没点赞 } ]
内容的提问来源于stack exchange,提问作者Sam Leurs
相关产品推荐
相关产品推荐

