基于MongoDB的类Facebook社交应用帖子多规则排序查询问询
MongoDB类Facebook应用帖子流排序实现方案
以下是基于你提供的Schema实现指定排序规则的聚合查询方案,注意:你的Schema中post和reaction集合缺少createdAt(创建时间)字段,这是实现近6个月反应差值和帖子创建时间排序的必要字段,需要先给这两个集合添加该字段。
核心思路
通过聚合管道的$lookup关联相关集合,计算出每个排序规则对应的数值字段,最后按优先级降序排序。
完整聚合查询(需替换currentUserId为实际当前用户ID)
db.post.aggregate([ // 1. 关联帖子作者的用户信息,获取作者的location_id { $lookup: { from: "user", localField: "author", foreignField: "_id", as: "authorInfo" } }, { $unwind: "$authorInfo" }, // 展开作者信息数组 // 2. 判断当前用户是否关注该作者 { $lookup: { from: "follow", let: { authorId: "$author" }, pipeline: [ { $match: { $expr: { $and: [ { $eq: ["$follower", ObjectId("currentUserId")] }, { $eq: ["$following", "$$authorId"] } ] } } } ], as: "isFollowed" } }, { $addFields: { isFollowed: { $cond: [{ $gt: [{ $size: "$isFollowed" }, 0] }, 1, 0] } } }, // 3. 统计帖子的评论数 { $lookup: { from: "comment", localField: "_id", foreignField: "post", as: "comments" } }, { $addFields: { commentCount: { $size: "$comments" } } }, // 4. 统计反应相关数据 { $lookup: { from: "reaction", localField: "_id", foreignField: "post", as: "reactions" } }, { $addFields: { // 统计正向反应数(like+love,用于计算热度) reactionHotCount: { $sum: { $map: { input: "$reactions", as: "r", in: { $cond: [{ $in: ["$$r.type", ["like", "love"]] }, 1, 0] } } } }, // 计算近6个月正向反应减悲伤反应的差值 recentReactionDiff: { $let: { vars: { recentReactions: { $filter: { input: "$reactions", cond: { $gte: ["$$this.createdAt", new Date(Date.now() - 6 * 30 * 24 * 60 * 60 * 1000)] } } } }, in: { $subtract: [ { $sum: { $map: { input: "$$recentReactions", as: "r", in: { $cond: [{ $in: ["$$r.type", ["like", "love"]] }, 1, 0] } } } }, { $sum: { $map: { input: "$$recentReactions", as: "r", in: { $cond: [{ $eq: ["$$r.type", "sad"] }, 1, 0] } } } } ] } } } } }, // 5. 计算帖子总热度:正向反应数+评论数 { $addFields: { postHotness: { $add: ["$reactionHotCount", "$commentCount"] } } }, // 6. 判断当前用户与作者是否同地区 { $lookup: { from: "user", pipeline: [ { $match: { _id: ObjectId("currentUserId") } }, { $project: { location_id: 1, _id: 0 } } ], as: "currentUserLocation" } }, { $unwind: "$currentUserLocation" }, { $addFields: { sameLocation: { $cond: [{ $eq: ["$authorInfo.location_id", "$currentUserLocation.location_id"] }, 1, 0] } } }, // 7. 按规则降序排序 { $sort: { isFollowed: -1, postHotness: -1, sameLocation: -1, recentReactionDiff: -1, createdAt: -1 } }, // 可选:保留业务需要的字段,过滤冗余数据 { $project: { content: 1, author: 1, createdAt: 1, isFollowed: 1, postHotness: 1 } } ])
各规则实现说明
- 用户是否关注作者:通过
$lookup关联follow集合,匹配当前用户为follower、作者为following的记录,用集合长度判断是否存在关注关系,转成1/0数值用于排序。 - 帖子热度:定义为「正向反应数(like+love)+评论数」,分别通过
$size统计评论数,$map+$sum统计正向反应数,相加得到总热度。 - 同一地区判断:关联当前用户的
location_id,与作者的location_id对比,相等则为1,否则为0。 - 近6个月反应差值:先通过
$filter筛选出近6个月的反应记录,再分别统计正向反应和悲伤反应的数量,计算差值。 - 帖子创建时间:依赖
post集合的createdAt字段,直接按该字段降序排序。
注意事项
- 必须给
post和reaction集合添加createdAt字段,否则无法实现时间相关的排序规则。 - 若数据量较大,建议给
follow(follower, following)、reaction(post, createdAt)、comment(post)等字段建立复合索引,提升聚合查询性能。 - 可根据业务需求调整
$project阶段的返回字段,减少数据传输量。
内容的提问来源于stack exchange,提问作者Michael Anachunam
相关产品推荐
相关产品推荐

