如何用MongoDB聚合查询找出与指定用户有共同点赞动态的用户及最多重合者
问题描述
现有likes集合,数据结构如下:
// 1 { "_id": ObjectId("1"), "masterid": ObjectId("45678"), // 动态发布者的用户ID "momentid": ObjectId("123456"),// 动态ID "userid": ObjectId("123456"), // 点赞者的用户ID "avatar": "1660531471959.jpg", // 点赞者头像 "username": "userA", // 点赞者用户名 "timestamp": NumberInt("1677072930") // 点赞时间戳 } // 2 { "_id": ObjectId("63f61d8d99b4ee0004e76e03"), "masterid": ObjectId("45678"), "momentid": ObjectId("123456"), "userid": ObjectId("45678"), "avatar": "defaultAvatar.jpg", "username": "userB", "timestamp": NumberInt("1677073805") }
需求:找出与用户A(userid为ObjectId("123456"))点赞过相同动态的其他用户,统计双方共同点赞的动态数量,最终确定共同点赞数量最多的用户。例如用户A点赞动态S、X,用户B点赞S,用户C点赞S、X、Y,需统计出B与A有1个共同动态,C与A有2个共同动态,C是共同数量最多的用户。
用户尝试了以下聚合查询但未成功:
db.likes.aggregate([ { $match: { userid: ObjectId("id") } }, { $group: { _id: "$momentid", count: { $sum: 1 }, users: { $addToSet: "$userid" } } }, { $lookup: { from: "likes", let: { users: "$users", momentid: "$_id" }, pipeline: [ { $match: { $expr: { $and: [ { $eq: [ "$momentid", "$$momentid" ] }, { $ne: [ "$userid", ObjectId("id") ] }, { $in: [ "$userid", "$$users" ] } ] } } }, { $project: { _id: 0, userid: 1 } } ], as: "otherLikes" } }, { $project: { _id: "$moment.userid", count: { $size: "$otherLikes.userid" }, users: "$otherLikes.userid" } }, { $sort: { count: -1 } } ])
问题分析与解决方案
原查询的问题在于:
$group阶段的users字段仅收集了用户A的ID,后续$lookup中的$in条件无实际意义;$project阶段引用了不存在的$moment.userid字段,导致结果异常;- 整体逻辑未正确关联用户A的点赞动态与其他用户的点赞记录,无法统计共同数量。
正确的聚合管道如下:
// 替换为用户A的实际ObjectId const userAId = ObjectId("123456"); db.likes.aggregate([ // 1. 获取用户A点赞过的所有动态ID { $match: { userid: userAId } }, { $group: { _id: null, userAMoments: { $addToSet: "$momentid" } } }, // 2. 关联likes集合,统计其他用户的共同点赞数量 { $lookup: { from: "likes", let: { targetMoments: "$userAMoments" }, pipeline: [ { $match: { $expr: { $and: [ { $in: [ "$momentid", "$$targetMoments" ] }, { $ne: [ "$userid", userAId ] } ] } } }, { $group: { _id: "$userid", commonCount: { $sum: 1 }, username: { $first: "$username" }, avatar: { $first: "$avatar" } } } ], as: "commonUsers" } }, // 3. 整理结果并按共同数量降序排序 { $unwind: "$commonUsers" }, { $replaceRoot: { newRoot: "$commonUsers" } }, { $sort: { commonCount: -1 } } ])
步骤说明
- 收集用户A的点赞动态:通过
$match筛选用户A的点赞记录,用$group将所有点赞过的动态ID存入数组; - 统计其他用户的共同动态数:利用
$lookup子管道,筛选出点赞过这些动态的非用户A记录,再按用户分组统计数量,同时保留用户名、头像信息; - 整理排序结果:展开数组并将子文档转为根文档,最后按共同数量降序排列,数量最多的用户排在最前。
内容的提问来源于stack exchange,提问作者lionjoy
相关产品推荐
相关产品推荐

