聚合管道MongoDB以避免多次查询

问题描述 投票:0回答:1

我有

post
这样的文件:

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

我当前的管道看起来像这样,其中包含

user_ids
要避免的用户 ID 数组和
seen_ids
还有要避免的帖子 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
的列表,按
likeNum
descending
排序,但每个
post
最多 2 个
userID

示例:

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},
]

注意:出于性能原因,我想要

aggregation
中的最少代码,不需要像示例输出中那样完美地格式化数据,除非它对性能没有影响,否则我更喜欢自己在代码中重新排序/转换对象只要我有正确的
post
列表内容(但不是特别格式化或排序)作为聚合的输出。

提前非常感谢!

mongodb aggregation-framework pymongo
1个回答
0
投票

您已经非常接近您所需要的了。

  1. $likeNum
    阶段之后按
    $match
    排序。

  2. 然后,当您

    $group
    用户 ID 时,您可以使用
    $firstN
    聚合累加器
    仅选择每个用户的前 2 个帖子。因此,这些将是每个用户 ID 的最高 2 个
    likeNum
    (因为我们之前已排序)。

    • 此外,使用
      "$$ROOT"
      获取实际的邮寄文档,而不仅仅是
      likeNum
  3. 然后展开累积的

    "$posts"
    ,将其替换为文档本身,并再次按
    likeNum
    排序。

(蓝色部分是与你的管道不同的部分。)

db.post.aggregate([
  {"$match": {"userID": {"$nin": user_ids}, "_id": {"$nin": seen_ids}}},
  { $sort: { likeNum: -1 } },
  {
    "$group": {
      "_id": "$userID",
      "posts": {
        $firstN: {
          input: "$$ROOT",
          n: 2
        }
      }
    }
  },
  { $unwind: "$posts" },
  { $replaceWith: "$posts" },
  { $sort: { likeNum: -1 } },
  { "$limit": 10 }
])

蒙戈游乐场。 (对第一个

$match
阶段没有任何更改,我只是将
"user3"
"uid9"
放在操场示例中。)

© www.soinside.com 2019 - 2024. All rights reserved.