我有
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
列表内容(但不是特别格式化或排序)作为聚合的输出。
提前非常感谢!
您已经非常接近您所需要的了。
在
$likeNum
阶段之后按$match
排序。
然后,当您
$group
用户 ID 时,您可以使用 $firstN
聚合累加器 仅选择每个用户的前 2 个帖子。因此,这些将是每个用户 ID 的最高 2 个likeNum
(因为我们之前已排序)。
"$$ROOT"
获取实际的邮寄文档,而不仅仅是 likeNum
。然后展开累积的
"$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"
放在操场示例中。)