web-dev-qa-db-ja.com

CouchDBのページ付け?

ページネーションに必要なクエリを実装するにはどうすればよいですか?

基本的に、ページ1が要求されたら、最初の5つのエントリを取得します。 2ページ目については、次の5つを取得します。

これをcouchdb-pythonモジュールを介して使用する予定ですが、実装に違いはありません。

44
dbr

CouchDBガイド ここにたくさんのサンプルコードを含むページネーションについての良い議論があります: http://guide.couchdb.org/draft/recipes.html#pagination ここにあります彼らのアルゴリズム:

  • ビューからrows_per_page + 1行をリクエストします
  • rows_per_page行を表示し、最後の行をnext_startkeyとして保存します
  • ページ情報として、startkeynext_startkeyを保持します
  • next_*値を使用して次のリンクを作成し、他の値を使用して前のリンクを作成します

注:CouchDBでページをフェッチする適切な方法は、想像するような開始インデックスではなく、開始キーを指定することです。しかし、2ページ目を開始するためのキーをどのように知っていますか?賢い解決策:「1ページに10行を要求する代わりに、11行を要求しますが、10行のみを表示し、11行目の値を次のページの開始キーとして使用します。」

複数のドキュメントが同一のキーを発行することが予想される場合は、startdocidに加えてstartkeyを使用して正しくページ付けする必要があります。その理由は、startkeyだけでは行を一意に識別するのに十分ではなくなるためです。 startkeyを指定しない場合、これらのパラメーターは役に立ちません。実際、CouchDBは最初にstartkeyパラメーターを調べ、次にstartdocidパラメーターを使用して、複数の潜在的な開始行のキーが同じでドキュメントIDが異なる場合に、範囲の先頭をさらに再定義します。 。 enddocidについても同じです。

32
AlexChaffee

CouchDB HTTP View API は、ページングを効率的に行うための十分な範囲を提供します。

最も簡単な方法は、startkeycountを使用します。 Countは、CouchDBがそのビューリクエストに対して返すエントリの最大数であり、設計次第です。startkeyは、CouchDBを開始する場所です。ビューをリクエストすると、エントリの数も表示されるので、ユーザーに表示したい場合は、ページの数を計算できます。

したがって、最初のリクエストではスタートキーを指定せず、表示するエントリ数のカウントのみを指定します。次に、返された最後のエントリのキーをメモし、それを次のページの開始キーとして使用できます。この単純なフォームでは、あるページの最後のエントリが次のページの最初のエントリであるオーバーラップが発生します。これが望ましくない場合は、ページの最後のエントリを表示しないことは簡単です。

これを行う簡単な方法は、skipパラメーターを使用してページの開始ドキュメントを作成することですが、この方法は注意して使用する必要があります。 skipパラメータを使用すると、内部エンジンは繰り返し処理しているエントリを返さないようになります。これにより目的の動作が得られますが、ページの最初のドキュメントをキーで見つけるよりもはるかに時間がかかります。スキップされるドキュメントが多いほど、リクエストは遅くなります。

13
Kerr

これは私がこれまでに思いついたものです-すべての投稿の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
1
dbr
  • 以下は私が見つけた再帰的な方法です:

    2つの変数を取る

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

                           });
  });

  }
0
Manvendra Jina