计算给定记录的跳过值以进行排序分页

Calculate skip value for given record for sorted paging

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

目前我正在选择所有记录并手动对结果数组进行索引。

这称为 "forward paging",这是一个概念,您可以在使用 "sorted" 结果时将结果 "efficiently page" 用于 "forward" 方向。

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 }

将这些 "already sorted" 文档(为了方便起见)作为我们希望 "page" 每页 "two" 项的结果示例。

在第一个例子中,你会做这样的事情:

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 是你存储在类似 "session variable" 的东西,可以在下一个 Web 应用程序请求时访问,或者类似的地方没有。

它们应该包含的是您排序的最后一个值以及自该值未更改后看到的 "unique" _id 值列表。因此:

lastVal = 3,
lastSeen = [1,2];

重点是,当 "next page" 的请求出现时,您希望将这些变量用于类似这样的事情:

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
});

所做的是 "exclude" 结果列表中 lastSeen 中记录的所有 _id 值,并确保所有结果都需要 "less than or equal to" (降序) lastVal 记录为排序字段 "a".

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

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

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

lastVal = 2,
lastSeen = [4];

所以现在的逻辑是您不需要排除之前看到的其他 _id 值,因为您实际上只是在寻找 "a" 的值而不是 "less than or equal to" lastVal 并且由于在该值处只看到 "one" _id 值,因此仅排除该值。

这当然会产生下一页,使用与上面相同的代码:

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

一般来说,这是 "forward page" 通过结果的最有效方法,对于 "sorted" 结果的高效分页特别有用。

但是,如果您想在任何阶段 "jump" 转页 20 或类似操作,那么这不适合您。你坚持使用传统的 .skip().limit() 方法来通过 "page number" 做到这一点,因为没有其他合理的方法来 "calculate" 这个。

所以这完全取决于您的应用程序如何实现 "paging" 以及您可以接受的内容。 .skip().limit() 方法受到 "skipping" 性能的影响,可以通过使用此处的方法来避免。

另一方面,如果您想要 "jump to page",那么 "skipping" 是您唯一真正的选择,除非您想要获得 "cache" 的结果。但这完全是另一个问题。