MongoDB聚合的高效分页?

时间:2014-01-17 18:12:12

标签: mongodb

为提高效率,Mongo文档建议限制语句紧跟在排序语句之后,最终会有点荒谬:

 collection.find(f).sort(s).limit(l).skip(p)

我说这有点荒谬,因为它似乎说先拿l项,然后放下那些l的第一个p。由于p通常大于l,你认为最终没有结果,但实际上你最终会得到l结果。

聚合比你期望的更多:

collection.aggregate({$unwind: u}, {$group: g},{$match: f}, {$sort: s}, {$limit: l}, {$skip: p})
如果p> gt; = l。

,则

返回0结果

collection.aggregate({$unwind: u}, {$group: g}, {$match: f}, {$sort: s}, {$skip: p}, {$limit: l})

有效,但文档似乎暗示如果匹配返回的结果集大于工作内存,则会失败。这是真的?如果是这样,是否有更好的方法对通过聚合返回的结果集执行分页?

来源:本页末尾的“版本2.4更改”评论:http://docs.mongodb.org/manual/reference/operator/aggregation/sort/

3 个答案:

答案 0 :(得分:10)

在MongoDB游标方法(即使用find()时)limitsortskip可以按任意顺序应用=>订单没关系。 find()返回应用了修改的游标。排序总是在限制之前完成,跳过也在限制之前完成。换句话说,订单是: sort - >跳过 - >限

聚合框架不返回数据库游标。相反,它返回带有聚合结果的文档。它的工作原理是在管道的每个步骤产生中间结果,因此操作顺序非常重要。

我猜MongoDB不支持游标修饰符方法的顺序,因为它在内部实现的方式。

您无法对聚合框架的结果进行分页,因为只有一个文档只包含结果。您仍然可以使用跳过和限制对常规查询进行分页,但更好的做法是使用范围查询,因为它使用索引的效率。

<强>更新

由于v2.6 Mongo聚合框架返回游标而不是单个文档。比较:v2.4v2.6

答案 1 :(得分:1)

  

文档似乎暗示如果匹配返回的结果集大于工作内存,则此(聚合)将失败。这是真的吗?

没有。例如,您可以在不使用$match运算符的情况下聚合大于物理内存的集合。它可能很慢,但它应该工作。如果$match返回大于RAM的内容,则没有问题。

以下是实际的管道限制。

http://docs.mongodb.org/manual/core/aggregation-pipeline-limits/

$match运算符不会导致内存问题。如文档中所述,$group$sort是常见的恶棍。它们是累积的,可能需要访问整个输入集才能生成任何输出。如果他们将太多数据加载到物理内存中,它们将会失败。

  

如果是这样,是否有更好的方法对通过聚合返回的结果集执行分页?

我已经正确地说你不能“聚合”(应用$skip$limit)聚合的结果,因为它只是一个MongoDB文档。但是您可以对聚合管道的中间结果进行“分页”。

在管道上使用$limit将有助于将结果集保持在16 MB边界内,即最大BSON文档大小。即使收集增长,你也应该是安全的。

$group可能会出现问题,特别是$sort。如果实际发生,您可以创建“排序友好”索引来处理它们。看看有关索引策略的文档。

http://docs.mongodb.org/manual/tutorial/sort-results-with-indexes/

最后,请注意$skip对性能没有帮助。相反,它们往往会减慢应用程序的速度,因为它会强制MongoDB扫描每个跳过的文档以达到集合中的所需点。

http://docs.mongodb.org/manual/reference/method/cursor.skip/

答案 2 :(得分:0)

$sort preceding $limit的MongoDB建议是绝对正确的,因为它会在发生前n个结果时优化执行该操作所需的内存。

仅仅是您提出的解决方案不适合您的用例,即分页。

您可以修改查询以从此优化中受益。

collection.aggregate([
  {
    $unwind: u
  }, 
  {
    $group: g
  },
  {
    $match: f
  }, 
  {
    $sort: s
  }, 
  {
    $limit: l+p
  },
  { 
    $skip: p
  }
]);

或用于find查询

 collection.find(f).sort(s).limit(l+p).skip(p)

尽管如此,您可以看到分页较大,即使进行了这种优化,内存也会越来越多。