You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

MongoDB聚合管道优化:实现单用户最多2篇帖子的降序查询

MongoDB聚合管道优化需求

文档结构

Post文档结构如下:

post = {
  "_id": "uid1",
  "userID": "user1",
  "likeNum": 30,
}

当前聚合管道

现有聚合管道使用$nin排除指定用户ID和已浏览帖子ID,结构如下:

fake_pipeline = [
            {'$match': {'userID': {'$nin': user_ids}, '_id': {"$nin": seen_ids}}},
            {'$group': {'_id': '$userID', 'posts': {'$push': '$likeNum'}}},
            {'$project': {'posts': {'$slice': [{'$sortArray': {'input': '$posts', 'sortBy': {'likeNum': -1}}}, 2]}}},
            {'$limit': 10}
        ]

需求

修改上述管道,实现:

  • 返回最多10条完整的post文档,每个userID对应的帖子不超过2条
  • 最终结果按likeNum降序排列(可在业务代码中完成排序,聚合管道尽量精简)

示例数据

数据库中的帖子列表:

post_list_in_db = [
  {"_id": "uid1", "userID": "user1", "likeNum": 29},
  {"_id": "uid2", "userID": "user1", "likeNum": 2},
  {"_id": "uid3", "userID": "user1", "likeNum": 13},
  {"_id": "uid4", "userID": "user2", "likeNum": 21},
  {"_id": "uid5", "userID": "user2", "likeNum": 19},
  {"_id": "uid6", "userID": "user3", "likeNum": 1},
  {"_id": "uid7", "userID": "user3", "likeNum": 8},
  {"_id": "uid8", "userID": "user3", "likeNum": 14},
  {"_id": "uid9", "userID": "user3", "likeNum": 4},
  {"_id": "uid10", "userID": "user4", "likeNum": 20},
  {"_id": "uid11", "userID": "user4", "likeNum": 9},
  {"_id": "uid12", "userID": "user4", "likeNum": 11},
]

预期输出

[
  {"_id": "uid1", "userID": "user1", "likeNum": 29},
  {"_id": "uid4", "userID": "user2", "likeNum": 21},
  {"_id": "uid10", "userID": "user4", "likeNum": 20},
  {"_id": "uid5", "userID": "user2", "likeNum": 19},
  {"_id": "uid8", "userID": "user3", "likeNum": 14},
  {"_id": "uid3", "userID": "user1", "likeNum": 13},
  {"_id": "uid12", "userID": "user4", "likeNum": 11},
  {"_id": "uid7", "userID": "user3", "likeNum": 8},
]

优化后的聚合管道

optimized_pipeline = [
    # 过滤排除指定用户和已浏览帖子
    {'$match': {'userID': {'$nin': user_ids}, '_id': {'$nin': seen_ids}}},
    # 按赞数降序排序,确保每组取到的是该用户最高赞的帖子
    {'$sort': {'likeNum': -1}},
    # 按用户分组,推送完整帖子文档到数组
    {'$group': {
        '_id': '$userID',
        'posts': {'$push': '$$ROOT'}
    }},
    # 每组只保留前2条帖子
    {'$project': {
        'posts': {'$slice': ['$posts', 2]}
    }},
    # 展开帖子数组为单个文档
    {'$unwind': '$posts'},
    # 将帖子内容恢复为根文档结构
    {'$replaceRoot': {'newRoot': '$posts'}},
    # 限制最多返回10条结果
    {'$limit': 10}
]

管道说明

  1. $match:保留原过滤逻辑,先剔除不需要的用户和已浏览帖子,减少后续处理的数据量,提升性能。
  2. $sort:全局按likeNum降序排序,保证后续分组时每组内的帖子是按赞数从高到低排列的,避免在分组内二次排序。
  3. $group:按userID聚合,使用$$ROOT推送完整的帖子文档,确保不会丢失字段。
  4. $project:用$slice截取每组的前2条帖子,满足单用户最多2条的限制。
  5. $unwind + $replaceRoot:将分组后的数组展开为单个完整的post文档,恢复原文档结构。
  6. $limit:限制最终结果最多10条。

如果需要严格的全局likeNum降序,可在业务代码中对聚合返回的结果再执行一次排序操作,这样能让聚合管道更精简,减少数据库端的计算压力。

内容的提问来源于stack exchange,提问作者Tom3652

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.17 17:05:56