在 Mongoose 和 Keystone 中,包含许多元素的分页速度非常慢

Pagination with many elements is incredibly slow in Mongoose and Keystone

版本:Keystone v4

我有一个 Mongo 数据库,其中包含超过 20k 个项目。我想要的是一个分页器,它允许用户一次快速滚动 Mongo 数据库 25 个元素。目前,此功能已实现,但服务器需要 >40 秒才能 return 结果,因为它查询整个(20k 项)数据库。但是,单个页面上只显示 25 个元素,所以我觉得如果只获取 25 个结果而不是 20k,应该会更快。我怎么能实现这个?我知道 .limit() 函数,但在使用该函数时我似乎无法弄清楚 keystone 中的分页。

当前代码:

var q = Items.model.find();
q.exec(function(err, newss) {
    console.log('There are %d', newss.length); // Prints out 20k number
    ...//skip

    locals.cnts = newss;

    // console.log(newss[0])

    locals.pagerr = pager({
        page: parseInt(req.query.page, 10) || 1,
        perPage: 25,
        total: newss.length
    });

    locals.itemsss = locals.cnts.slice(
        locals.pagerr.first - 1,
        locals.pagerr.last
    );
                
    next();

})

在当前的实现中,return 分页结果需要 >40 秒。我该如何解决这个问题?

您在此处使用的 model.find() 函数等同于 Mongoose find() function。由于您在没有任何过滤器的情况下调用它,此代码每次 运行 时都会 从数据库 中检索所有 25k 项。此数据正在传输到 Web server/node 进程,其中 function(err, newss) {...} 函数的主体是 运行。只有 然后 是你从集合中提取后的 25 个项目。

相反,如果你想像这样使用基于偏移量的分页,你应该使用 query.limit() and query.skip() functions. If you need to count the total items first, do so in a separate query using query.count().

我还没有测试过这段代码(自从我使用 Mongoose 以来已经有一段时间了),但我想你想要这样的东西:

// Warning! Untested example code
Items.model.find().count(function (err, count) {
  console.log('There are %d', count);

  locals.pager = pager({
    page: parseInt(req.query.page, 10) || 1,
    perPage: 25,
    total: count
  });

  Items.model.find()
    .skip(locals.pager.first)
    .limit(25)
    .exec(function(err, results) {
      locals.results = results;
      next();
    });
});

更笼统地说——如果您喜欢 Keystone 并想使用 Mongo,请留意 Keystone 6 updates. Keystone 6 uses Prisma 2 as it's ORM layer and they recently released support for Mongo。一旦该功能生产准备就绪,我们也会在 Keystone 中支持它。