为排序分页计算给定记录的跳过值


Calculate skip value for given record for sorted paging

我正在尝试使用php驱动程序计算mongo db集合中给定记录的跳过值。取一个给定的记录,找出这个记录在整个集合中的索引。这可能吗?

目前我选择所有的记录和手动做的结果数组的索引。

这被称为"前向分页"这是一个概念,当使用"排序"结果时,你可以使用它在"前向"方向"有效地分页"结果。

包含JavaScript逻辑(因为它在shell中工作),但并不难翻译。

一般概念:

{ "_id": 1, "a": 3 },
{ "_id": 2, "a": 3 },
{ "_id": 3, "a": 3 },
{ "_id": 4, "a": 2 },
{ "_id": 5, "a": 1 },
{ "_id": 6, "a": 0 }

考虑那些"已经排序"的文档(为了方便)作为我们希望每页按"两个"项"page"的结果示例。

在第一个实例中,你像这样做:

var lastVal = null,
    lastSeen = [];
db.collection.find().sort({ "a": -1 }).limit(2).forEach(function(doc) {
    if ( lastVal != doc.a ) {
        lastSeen = [];
    }
    lastVal = doc.a;
    lastSeen.push( doc._id );
    // do something useful with each document matched
});

现在这些lastVallastSeen是你存储在类似"会话变量"的东西,可以在web应用程序的下一个请求中访问,或者其他类似的东西。

它们应该包含的是您正在排序的最后一个值以及由于该值没有改变而看到的"唯一"_id值列表。因此:

lastVal = 3,
lastSeen = [1,2];
关键是,当"下一页"的请求出现时,你想要使用这些变量像这样:
var lastVal = 3,
    lastSeen = [1,2];
db.collection.find({ 
    "_id": { "$nin": lastSeen }, 
    "a": { "$lte": lastVal }
}).sort({ "a": -1 }).limit(2).forEach(function(doc) {
    if ( lastVal != doc.a ) {
        lastSeen = [];
    }
    lastVal = doc.a;
    lastSeen.push( doc._id );
    // do something useful with each document matched
});

这做的是"排除"lastSeen从结果列表中记录的_id的所有值,以及确保所有结果需要"小于或等于"(降序)lastVal记录的排序字段"a"。

这将在集合中产生接下来的两个结果:

{ "_id": 3, "a": 3 },
{ "_id": 4, "a": 2 },

但是经过处理后,我们的值现在看起来像这样:

lastVal = 2,
lastSeen = [4];

所以现在的逻辑是,你不需要排除之前看到的其他_id值,因为你只是在寻找"a"的值,而不是"小于或等于"lastVal,因为只有"一个"_id值在那个值上,所以只排除那个。

这当然会导致下一页使用与上面相同的代码:

{ "_id": 5, "a": 1 },
{ "_id": 6, "a": 0 }

一般来说,这是通过结果"转发页面"的最有效方式,对于"排序"结果的高效分页特别有用。

如果你想在任何阶段"跳转"到20页或类似的动作,那么这并不适合你。您只能使用传统的.skip().limit()方法来通过"页码"来完成此操作,因为没有其他合理的方法来"计算"它。

所以这完全取决于你的应用程序如何实现"分页"以及你能接受什么。.skip().limit()方法存在"跳过"的性能,可以通过使用这里的方法来避免。

另一方面,如果你想"跳转到页面",那么"跳过"是你唯一真正的选择,除非你想建立一个"缓存"的结果。但这完全是另一个问题。