3

当您基于单个唯一字段进行分页时,远程分页会被切断和干燥,但是如果有的话,它是如何工作的,如果有的话,在具有非唯一字段的情况下,也许一次有几个?

TL;DR:使用基于范围的分页对“高级搜索”类型的查询进行分页和排序是否合理或可能?这意味着对用户选择的、可能是非唯一的字段进行查询和排序。

例如,假设我想对文字游戏中播放的文字文档的搜索进行分页。假设每个文档都有一个score和一个word,我想让用户对这些字段进行过滤和排序。这两个领域都不是唯一的。假设有问题的字段有一个排序索引。

从简单的开始,假设用户想要查看得分为 10 的所有单词:

// page 1
db.words.find({score: 10}).limit(pp)
// page 2, all words with the score, ranged on a unique _id, easy enough!
db.words.find({score: 10, _id: {$gt: last_id}}).limit(pp)

但是如果用户想要得到所有分数低于 10 的单词怎么办?

// page 1
db.words.find({score: {$lt: 10}}).limit(pp)
// page 2, getting ugly...
db.words.find({
  // OR because we need everything lt the last score, but also docs with
  // the *same* score as the last score we haven't seen yet
  $or: [
    {score: last_score, _id: {$gt: last_id}},
    {score: {$lt: last_score}
  ]
}).limit(pp)

现在,如果用户想要分数小于 10 且字母值大于“FOO”的单词怎么办?查询的复杂性迅速升级,这仅适用于具有默认排序的搜索表单的一种变体。

// page 1
db.words.find({score: {$lt: 10}, word: {$gt: "FOO"}}).limit(pp)
// page 2, officially ugly.
db.words.find({
  $or: [
    // triple OR because now we need docs that have the *same* score but a 
    // higher word OR those have the *same* word but a lower score, plus 
    // the rest
    {score: last_score, word: {$gt: last_word}, _id: {$gt: last_id}},
    {word: last_word, score: {$lt: last_score}, _id: {$gt: last_id}},
    {score: {$lt: last_score}, word: {$gt: last_word}}
  ]
}).limit(pp)

我想为这种模式编写一个查询构建器是可行的,但它看起来非常混乱且容易出错。我倾向于退回以跳过具有上限结果大小的分页,但如果可能的话,我想使用范围分页。我对这将如何工作的想法完全错误吗?有没有更好的办法?

编辑:为了记录...

到目前为止,没有可行的替代方案,我实际上只是使用基于跳过的分页和有限的结果集,以保持跳过可管理。就我的目的而言,这实际上就足够了,因为没有真正需要搜索然后分页到数千个。

4

1 回答 1

1

您可以通过对唯一字段进行排序并将该字段的值保存为最后一个结果来获得范围分页。例如:

// first page
var page = db.words.find({
    score:{$lt:10},
    word:{$gt:"FOO"}
}).sort({"_id":1}).limit(pp);

// Get the _id from the last result
var page_results = page.toArray();
var last_id = page_results[page_results.length-1]._id;

// Use last_id to get your next page
var next_page = db.words.find({
    score:{$lt:10},
    word:{$gt:"FOO"},
    _id:{$gt:last_id}
}).sort({"_id":1}).limit(pp);
于 2013-09-18T19:43:55.173 回答