【问题标题】:Calculate skip value for given record for sorted paging为排序分页计算给定记录的跳过值
【发布时间】:2015-08-26 17:27:46
【问题描述】:

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

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

【问题讨论】:

    标签: php mongodb mongodb-query mongodb-php


    【解决方案1】:

    这称为“前向分页”,当使用“排序”结果时,您可以使用这个概念“有效地分页”通过“前向”方向的结果。

    包含 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 }
    

    将那些“已经排序”的文档(为了方便)作为我们希望每页“分页”“两个”项目的结果示例。

    在第一种情况下,您可以这样做:

    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 的所有值,并确保所有结果都需要“小于或等于”(降序排列) 为排序字段“a”记录的lastVal

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

    { "_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() 方法存在“跳过”的性能,可以通过使用此处的方法来避免。

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

    【讨论】:

    • 很棒的答案,非常感谢:)
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-12-10
    • 2012-07-28
    • 1970-01-01
    相关资源
    最近更新 更多