当您基于单个唯一字段进行分页时,激活的分页会被切断并干燥,但是如果有非独特字段的情况(如果有的话),它一般是如何工作的?
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)
我认为为这种模式编写查询构建器是可行的,但它看起来非常混乱且容易出错。我倾向于退回以跳过具有上限结果大小的分页,但是如果可能的话我想使用远程分页。在思考如何运作时,我完全错了吗?还有更好的方法吗?
到目前为止,由于没有可行的替代方案,我实际上只是使用基于跳过的分页和有限的结果集,保持跳过可管理。就我的目的而言,这实际上是足够的,因为没有必要搜索然后分页成千上万。
答案 0 :(得分: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);