简体   繁体   English

CouchDB中的分页?

[英]Pagination in CouchDB?

How would I go about implementation the queries required for pagination? 我将如何实现分页所需的查询?

Basically, when page 1 is requested, get the first 5 entries. 基本上,当请求第1页时,获取前5个条目。 For page 2, get the next 5 and so on. 对于第2页,获取下一个5,依此类推。

I plan to use this via the couchdb-python module, but that shouldn't make any difference to the implementation. 我计划通过couchdb-python模块使用它,但这不会对实现产生任何影响。

The CouchDB Guide has a good discussion of pagination, including lots of sample code, here: http://guide.couchdb.org/draft/recipes.html#pagination Here's their algorithm: CouchDB指南对分页进行了很好的讨论,包括大量示例代码,这里是: http//guide.couchdb.org/draft/recipes.html#pagination这是他们的算法:

  • Request rows_per_page + 1 rows from the view 从视图中请求rows_per_page + 1
  • Display rows_per_page rows, store last row as next_startkey 显示rows_per_page行,将最后一行存储为next_startkey
  • As page information, keep startkey and next_startkey 作为页面信息,请保持startkeynext_startkey
  • Use the next_* values to create the next link, and use the others to create the previous link 使用next_*值创建下一个链接,并使用其他链接创建上一个链接

NB: The proper way to fetch pages in CouchDB is by specifying a starting key, not a starting index like you might think. 注意:在CouchDB中获取页面的正确方法是指定一个起始键,而不是你想象的起始索引。 But how do you know what key to start the 2nd page on? 但是你怎么知道开始第2页的关键是什么? The clever solution: "Instead of requesting 10 rows for a page, you request 11 rows, but display only 10 and use the values in the 11th row as the startkey for the next page." 聪明的解决方案:“不是为页面请求10行,而是请求11行,但只显示10行,并使用第11行中的值作为下一页的开始键。”

If you expect to have multiple documents emit identical keys, you'll need to use startdocid in addition to startkey to paginate correctly. 如果你希望有多个文件发出相同的密钥,你需要使用startdocid除了startkey正确分页。 The reason is that startkey alone will no longer be sufficient to uniquely identify a row. 原因是单独的startkey将不再足以唯一地标识行。 Those parameters are useless if you don't provide a startkey . 如果您不提供startkey那些参数将无用。 In fact, CouchDB will first look at the startkey parameter, then it will use the startdocid parameter to further redefine the beginning of the range if multiple potential staring rows have the same key but different document IDs. 事实上,CouchDB将首先查看startkey参数,然后如果多个潜在的凝视行具有相同的密钥但文档ID不同,它将使用startdocid参数进一步重新定义范围的开头。 Same thing for the enddocid . enddocid也是enddocid

The CouchDB HTTP View API gives plenty of scope to do paging efficiently. CouchDB HTTP View API提供了足够的范围来有效地进行分页。

The simplest method would use startkey and count . 最简单的方法是使用startkeycount Count is the max number of entries CouchDB will return for that view request, something that is up to your design, and startkey is where you want CouchDB to start. Count是CouchDB将为该视图请求返回的最大条目数,这取决于您的设计,startkey是您希望CouchDB启动的位置。 When you request the view it will also tell you how many entries there are, allowing you to calculate how many pages there will be if you want to show that to users. 当您请求视图时,它还会告诉您有多少条目,允许您计算如果要向用户显示该条目的页数。

So the first request would not specify a startkey, just the count for the number of entries you want to show. 因此,第一个请求不会指定启动键,只会指定要显示的条目数。 You can then note the key of the last entry returned and use that as the start key for the next page. 然后,您可以记下返回的最后一个条目的键,并将其用作下一页的开始键。 In this simple form, you will get an overlap, where the last entry of one page is the first of the next. 在这个简单的表单中,您将获得重叠,其中一个页面的最后一个条目是下一个页面的第一个条目。 If this is not desirable it is trivial to simply not display the last entry of the page. 如果这不可取,那么简单地不显示页面的最后一个条目是微不足道的。

A simpler method of doing this is to use the skip parameter to work out the starting document for the page, however this method should be used with caution. 更简单的方法是使用skip参数计算页面的起始文档,但是应谨慎使用此方法。 The skip parameter simply causes the internal engine to not return entries that it is iterating over. skip参数只是导致内部引擎不返回它正在迭代的条目。 While this gives the desired behaviour it is much slower than finding the first document for the page by key. 虽然这给出了期望的行为,但它比按键查找页面的第一个文档慢得多。 The more documents that are skipped, the slower the request will be. 跳过的文档越多,请求就越慢。

This is what I have came up with so far - to get the ids of all posts, then retrieve the actual items for the first x number of IDs.. 这就是我到目前为止所提出的 - 获取所有帖子的ID,然后检索前x个ID的实际项目。

It's not terribly efficient, but more so than retrieving all the posts, then throwing most of the away. 这不是非常有效,但比检索所有帖子更重要,然后扔掉大部分。 That said, to my surprise, it seemed to run quite quickly - I ran the posthelper.page() method 100 times and it took about 0.5 seconds. 这就是说,令我惊讶的是,它似乎运行得很快 - 我运行了posthelper.page()方法100次,大约需要0.5秒。

I didn't want to post this in the actual question, so it wouldn't influence the answers as much - here's the code: 我不想在实际问题中发布这个,所以它不会影响答案 - 这是代码:

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
  • Here below is the recursive way I found : 下面是我发现的递归方式:

    Take two variables 拿两个变量

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

                           });
  });

  }

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM