【问题标题】:Pagination in CouchDB?CouchDB 中的分页?
【发布时间】:2010-09-23 15:40:39
【问题描述】:

我将如何实现分页所需的查询?

基本上,当请求第 1 页时,获取前 5 个条目。对于第 2 页,获取下一个 5,依此类推。

我计划通过 couchdb-python 模块使用它,但这对实现没有任何影响。

【问题讨论】:

    标签: pagination couchdb


    【解决方案1】:

    这是我到目前为止所想出的——获取所有帖子的 ID,然后检索前 x 个 ID 的实际项目..

    这不是非常有效,但比检索所有帖子,然后扔掉大部分更有效。也就是说,令我惊讶的是,它似乎运行得相当快——我运行了 posthelper.page() 方法 100 次,只用了大约 0.5 秒。

    我不想在实际问题中发布此内容,因此它不会对答案产生太大影响 - 这是代码:

    allPostsUuid = """
    function(doc) {
    if(doc.type == 'post'){
        emit(doc._id, null);
    }
    }
    """
    
    class PostsHelper:
        def __init__(self):
            server = Server(config.dbhost)
            db = server[config.dbname]
            return db
    
    
        def _getPostByUuid(self, uuid):
            return self.db.get(uuid)
    
        def page(self, number = 1):
            number -= 1 # start at zero offset
            start = number * config.perPage
            end = start + config.perPage
    
            allUuids = [
                x.key for x in self.db.query(allPostsUuid)
            ]
            ret = [
                self._getPostByUuid(x) for x in allUuids[start : end]
            ]
    
            if len(ret) == 0:
                raise Error404("Invalid page (%s results)" % (len(allUuids)))
            else:
                return ret
    

    【讨论】:

      【解决方案2】:

      CouchDB HTTP View API 为高效分页提供了充足的空间。

      最简单的方法是使用startkeycount。 Count 是 CouchDB 将为该视图请求返回的最大条目数,这取决于您的设计,而 startkey 是您希望 CouchDB 开始的位置。当您请求查看时,它还会告诉您有多少条目,如果您想向用户显示,您可以计算有多少页面。

      所以第一个请求不会指定开始键,只是要显示的条目数的计数。然后,您可以记下返回的最后一个条目的键,并将其用作下一页的开始键。在这个简单的表单中,您将获得重叠,其中一个页面的最后一个条目是下一个页面的第一个条目。如果这是不可取的,那么简单地不显示页面的最后一个条目是微不足道的。

      执行此操作的更简单方法是使用 skip 参数计算页面的起始文档,但应谨慎使用此方法。跳过参数只是导致内部引擎不返回它正在迭代的条目。虽然这提供了所需的行为,但它比按键查找页面的第一个文档要慢得多。跳过的文档越多,请求就越慢。

      【讨论】:

      • 啊哈!从您链接的那个页面:count 参数可以与“skip=要跳过的行数”结合使用。完美。
      • 我已将以上信息添加到您的回答中(仅供参考),希望您不要介意!
      • 我又编辑了一遍。在大多数情况下,使用跳过并不是一个好方法。
      • 不,要找到第 n 个条目,您需要遍历索引树,因为您不知道树中的一个分支有多少条目。您可以更快地找到特定的密钥。
      • 查看您发布的链接,我发现没有“计数”选项。有一个“限制”选项。也许它被改变了?
      【解决方案3】:

      CouchDB Guide 对分页进行了很好的讨论,包括大量示例代码,这里:http://guide.couchdb.org/draft/recipes.html#pagination 这是他们的算法:

      • 从视图中请求 rows_per_page + 1
      • 显示rows_per_page 行,将最后一行存储为next_startkey
      • 作为页面信息,保留startkeynext_startkey
      • 使用next_* 值创建下一个链接,并使用其他值创建上一个链接

      注意:在 CouchDB 中获取页面的正确方法是指定一个起始键,而不是您可能认为的起始索引。但是你怎么知道开始第二页的键是什么?巧妙的解决方案:“不是为一页请求 10 行,而是请求 11 行,但只显示 10 行,并使用第 11 行中的值作为下一页的开始键。”

      如果您希望多个文档发出相同的键,则除了使用startkey 之外,您还需要使用startdocid 才能正确分页。原因是单独的startkey 将不再足以唯一标识一行。如果您不提供startkey,这些参数将毫无用处。实际上,CouchDB 会首先查看startkey 参数,然后如果多个潜在的起始行具有相同的键但不同的文档ID,它将使用startdocid 参数进一步重新定义范围的开头。 enddocid 也是如此。

      【讨论】:

      • 这种方法的问题是你不能真正点击多次,只能点击一次。当您转到下一页时,您要么必须手动索引所有可能的首页首页,要么您只能返回一页,然后您没有任何信息可以转到另一页。
      • 对于那些在这里绊倒并陷入@for3st 困境的人来说,数组的自然特性有助于解决这个问题。通过push()上一页开始_id进入数组你可以很容易地pop()数组_id点击上一页。最多你要做的就是跟踪一个整数数组。
      【解决方案4】:
      • 下面是我找到的递归方式:

        取两个变量

        var lastOffset = 0; var counter = 0;
      
        function someRecursive(lastOffset,counter) {
      
        queryView(db, whereClause).then(result => {
            var rows_per_page = 5; 
      
      //formula below 
      var page = Math.floor((lastOffset == 0 ? 0: (result.offset - lastOffset) +
      
        (rows_per_page * counter)) /  rows_per_page) + 1;
      
         var skip = page * rows_per_page;
        if (somerecursionexitcondition) {
                         counter = lastOffset == 0 ? lastOffset: counter + 1;
                         lastOffset =result.offset;
                    someRecursive(lastOffset, counter).then(result => {
                                     resolve();
      
                                 });
        });
      
        }
      

      【讨论】:

        猜你喜欢
        • 2011-03-06
        • 2017-02-16
        • 2011-04-08
        • 1970-01-01
        • 1970-01-01
        • 2017-05-26
        • 2011-03-08
        • 2014-03-03
        • 1970-01-01
        相关资源
        最近更新 更多