【问题标题】:How to order MongoDB Aggregation with match, sort, and limit如何使用匹配、排序和限制对 MongoDB 聚合进行排序
【发布时间】:2013-06-11 20:36:51
【问题描述】:

我目前的聚合是:

db.group_members.aggregate({
  $match: { user_id: { $in: [1,2,3] } }
}, {
  $group: { _id: "$group_id" }
}, {
  $sort: { last_post_at: -1 }
}, {
  $limit: 5
})

对于文档结构:

{
  _id: '...',
  user_id: '...',
  group_id: '...',
  last_post_at: Date,
}

我在{user_id: 1, last_post_at: -1}上也有一个索引

既然我的索引已经在last_post_at 上,那么排序没用吗?我不是 100% 确定这个顺序。

我的最终目标是复制这个 SQL:

SELECT DISTINCT ON (group_id)
FROM group_members
WHERE user_id in [1,2,3]
ORDER_BY last_post_at DESC
LIMIT 5

我想知道如何使它对一个非常大的 group_members 具有高性能并且仍然以正确的顺序返回它。

更新: 我希望找到一种解决方案来限制加载到内存中的文档数量。这将是一个相当大的集合并且非常频繁地访问。

【问题讨论】:

  • 您在 $group 阶段缺少分组操作 - 您想要 last_post:{$max:"$last_post_at"} 或类似的东西。
  • 那是否还需要将 user_id: { $in: [1,2,3] } 的整个子集存储在内存中?
  • 该组必须遍历所有匹配的文档 - 因为您的排序和限制基于 aggregated 值,因此不能在组之前进行限制。可以想象,可以对组之前的每个 user_id 值进行排序和限制的优化,但目前在 2.4 MongoDB 中尚未实现。

标签: mongodb aggregation-framework


【解决方案1】:

将$sort放在$group之前,否则MongoDB无法使用索引来帮助排序。

但是,在您的查询中,与 group_members 集合的总大小相比,您希望查询相对较少的 user_id。所以我只推荐一个关于 user_id 的索引。在这种情况下,MongoDB 将不得不按 last_post_at 对内存中的结果进行排序,但这是值得的,以换取使用 user_id 进行初始查找的索引。

【讨论】:

  • 排序不是先将整个集合加载到内存中吗?
  • 不,如果您在排序字段上有索引,则不会。如果您确实有这样的索引,MongoDB 只会按排序顺序对其进行迭代。否则,它会尝试对内存中的所有内容进行排序,如果它使用超过 10%(我认为)的 RAM,则会中止。
  • 我最终选择了第二种选择,经过一些基准测试后,它的速度比我预期的要快得多。
猜你喜欢
  • 1970-01-01
  • 2015-12-13
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-05-30
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多