MongoDB聚合的有效分页?

MongoDB聚合的有效分页?,mongodb,Mongodb,为了提高效率,Mongo文档建议limit语句紧跟在sort语句之后,这样就有点荒谬了: 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}, {

为了提高效率,Mongo文档建议limit语句紧跟在sort语句之后,这样就有点荒谬了:

 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>=l,则返回0个结果

collection.aggregate({$unwind: u}, {$group: g}, {$match: f}, {$sort: s}, {$skip: p}, {$limit: l})
工作正常,但文档似乎暗示,如果匹配返回的结果集大于工作内存,则此操作将失败。这是真的吗?如果是这样,是否有更好的方法对通过聚合返回的结果集执行分页

来源:本页末尾的“在版本2.4中更改”注释:

在MongoDB游标方法中(即使用
find()
时),如
limit
sort
skip
可以以任何顺序应用=>顺序不重要。
find()
返回应用修改的光标。排序总是在限制之前完成,跳过也是在限制之前完成。换句话说,顺序是:排序->跳过->限制

聚合框架不返回DB游标。相反,它返回一个包含聚合结果的文档。它的工作原理是在管道的每一步产生中间结果,因此操作顺序确实很重要

我猜MongoDB不支持order for cursor修饰符方法,因为它是在内部实现的

您不能对聚合框架的结果进行分页,因为只有一个文档具有结果。您仍然可以使用skip和limit对常规查询进行分页,但更好的做法是使用范围查询,因为它使用索引的效率很高

更新:

因为v2.6 Mongo聚合框架返回一个游标而不是一个文档。比较:和

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

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

以下是实际的管道限制

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

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

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

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

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

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

MongoDB推荐的绝对正确,因为当它发生时,它优化了为前n个结果执行操作所需的内存

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

您可以修改查询以从优化中获益

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

或用于
查找
查询

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


但是,正如您所看到的,使用大分页时,即使进行了此优化,内存也会越来越大。

我现在正在聚合上分页,但我们的集合中只有~50000个项目。我只是想知道,随着收藏的增加,这件事是否会对我产生影响。如果没有解决方法,我将不得不进行更多的非规范化以避免聚合。如果聚合命令的结果不适合1个文档的大小,则将出现错误。通常,在不使用sql数据库的情况下,您会调整模式/数据以匹配最常见的查询在分页场景中,skip将很小——没有人查看第2056页。所以这不是一个问题。有很多很好的信息,但没有完全回答我的问题。从文档中可以清楚地看出,管道中的
$sort
后跟
$limit
对于我的需要是安全的。我的问题是:
$sort
后面跟着一个小的
$skip
,后面跟着一个
$limit
?在
$sort
之后使用一个小的
$skip
然后
$limit
是安全的。