使用Mongoose跳过大量记录时如何避免内存限制?

时间:2017-09-19 13:18:33

标签: mongodb indexing mongoose

在具有超过100k记录的集合上,当我使用Mongoose选项查询时:

contact.find({}, {}, {
  collation: {
    locale: 'en_US',
    strength: 1
  },
  skip: 90000,
  limit: 10,
  sort: {
    email: 1
  }
});

我收到此错误:

MongoError:查找命令期间执行程序错误:OperationFailed:排序操作使用的RAM超过最大33554432字节。添加索引,或指定较小的限制。

但我确实在电子邮件字段中有索引:

{
  "v" : 2,
  "key" : {
    "email" : 1
  },
  "name" : "email_1",
    "ns" : "leadfox.contact",
    "background" : true
}

另一方面,当我在Mongo shell中查询时,它工作正常:

db.contact.find().sort({email: 1}).skip(90000).limit(10)

1 个答案:

答案 0 :(得分:1)

您遇到的是skip。正如您在documentation

中看到的那样
  

cursor.skip()方法通常很昂贵,因为它要求服务器从集合或索引的开头走,以在开始返回结果之前获取偏移或跳过位置。随着偏移量(例如上面的pageNumber)的增加,cursor.skip()将变得更慢并且CPU密集度更高。对于较大的集合,cursor.skip()可能会成为IO绑定。

你应该找到一个更好的方法而不是跳过。当您使用email字段对文档进行排序时,您可以使用电子邮件字段而不是skip编写范围查询

contact.find({ "email": { $gt: the_last_email_from_previous_query } }, {}, {
  collation: {
    locale: 'en_US',
    strength: 1
  },
  limit: 10,
  sort: {
    email: 1
  }
});

更新:

首先。就像我上面说的那样,你想要的是不可能的。 Mongodb说,而不是我。

其次,我建议您搜索现代分页方法和人们使用案例。你在评论中的例子是荒谬的。对于任何数据,没有用户应该/将直接转到第790页。如果他们直接进入这样的页面,很可能意味着,他们将数据覆盖到第790页并且他们想要继续。因此,即使您正在构建无状态系统(如同所有现代系统一样),您应该存储有关用户最终点视图的一些信息,以用于分页数据。这是一个基于用户行为的示例方法(我不是说最好,它只是一个例子)。

另一种方法,您可以使用(像大多数现代分页表一样),您只允许用户向前或向后导航5-6页。因此,您只能在$gt字段中与$ltemail一起跳过查询中的50-60文档。

另一种方法可以是使用其他一些工具在内存中缓存数据。

我想你得到的照片。快乐的编码。