質問
ページネーションに必要なクエリを実装するにはどうすればよいですか?
基本的に、ページ1が要求されると、最初の5つのエントリを取得します。 2ページ目では、次の5つを取得します。
これをcouchdb-pythonモジュール経由で使用する予定ですが、それによって実装に違いが生じることはありません。
解決
CouchDBガイドでは、多くのサンプルコードを含むページネーションについて詳しく説明しています。 http://guide.couchdb.org/draft/recipes.html#pagination アルゴリズムは次のとおりです。
- ビューからの
rows_per_page + 1
行のリクエスト -
rows_per_page
行を表示し、最後の行をnext_startkey
として保存します
- ページ情報として、
startkey
とnext_startkey
を保持します
-
next _ *
の値を使用して次のリンクを作成し、他の値を使用して前のリンクを作成します
N.B .: CouchDBでページを取得する適切な方法は、あなたが考えるような開始インデックスではなく、開始キーを指定することです。しかし、2番目のページを開始するキーをどのようにして知るのでしょうか?賢い解決策:"ページに10行を要求する代わりに、11行を要求しますが、10行のみを表示し、11行目の値を次のページの開始キーとして使用します。"
複数のドキュメントが同一のキーを発行することが予想される場合、正しくページネーションするには、 startkey
に加えて startdocid
を使用する必要があります。その理由は、行を一意に識別するには startkey
だけでは不十分だからです。 startkey
を提供しない場合、これらのパラメーターは役に立ちません。実際、CouchDBは最初に startkey
パラメーターを確認し、次に startdocid
パラメーターを使用して、複数の潜在的なスター行に同じキーがある場合、範囲の先頭をさらに再定義しますただし、異なるドキュメントID。 enddocid
についても同様です。
他のヒント
CouchDB HTTP View API は、ページングを効率的に行うための十分な範囲を提供します。
最も簡単な方法は、 startkey
と count
を使用します。 Countは、そのビューリクエストに対してCouchDBが返すエントリの最大数であり、設計次第であり、startkeyはCouchDBを開始する場所です。ビューをリクエストすると、エントリの数も表示されるため、ユーザーに表示したいページ数を計算できます。
したがって、最初のリクエストではスタートキーは指定せず、表示するエントリ数のカウントのみを指定します。次に、返された最後のエントリのキーを書き留めて、次のページの開始キーとして使用できます。この単純な形式では、1ページの最後のエントリが次のページの最初のエントリであるオーバーラップが表示されます。これが望ましくない場合は、単にページの最後のエントリを表示しないようにするのは簡単です。
これを行う簡単な方法は、ページの開始ドキュメントを処理するためにskipパラメーターを使用することですが、この方法は注意して使用する必要があります。 skipパラメーターは、内部エンジンが繰り返し処理中のエントリを返さないようにします。これは望ましい動作を提供しますが、キーごとにページの最初のドキュメントを見つけるよりもはるかに遅くなります。スキップされるドキュメントが多いほど、リクエストは遅くなります。
これは私がこれまでに思いついたものです-すべての投稿のIDを取得し、IDの最初のx個の実際のアイテムを取得します。
これは非常に効率的ではありませんが、すべての投稿を取得してから、ほとんどを捨てるよりも効率的です。とはいえ、驚いたことに、非常に高速に実行されているように見えました- 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つの変数を取る
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();
});
});
}