ページネーションに必要なクエリを実装するにはどうすればよいですか?
基本的に、ページ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_*
値を使用して次のリンクを作成し、他の値を使用して前のリンクを作成します注:CouchDBでページをフェッチする適切な方法は、想像するような開始インデックスではなく、開始キーを指定することです。しかし、2ページ目を開始するためのキーをどのように知っていますか?賢い解決策:「1ページに10行を要求する代わりに、11行を要求しますが、10行のみを表示し、11行目の値を次のページの開始キーとして使用します。」
複数のドキュメントが同一のキーを発行することが予想される場合は、startdocid
に加えてstartkey
を使用して正しくページ付けする必要があります。その理由は、startkey
だけでは行を一意に識別するのに十分ではなくなるためです。 startkey
を指定しない場合、これらのパラメーターは役に立ちません。実際、CouchDBは最初にstartkey
パラメーターを調べ、次にstartdocid
パラメーターを使用して、複数の潜在的な開始行のキーが同じでドキュメントIDが異なる場合に、範囲の先頭をさらに再定義します。 。 enddocid
についても同じです。
CouchDB HTTP View API は、ページングを効率的に行うための十分な範囲を提供します。
最も簡単な方法は、startkey
とcount
を使用します。 Countは、CouchDBがそのビューリクエストに対して返すエントリの最大数であり、設計次第です。startkeyは、CouchDBを開始する場所です。ビューをリクエストすると、エントリの数も表示されるので、ユーザーに表示したい場合は、ページの数を計算できます。
したがって、最初のリクエストではスタートキーを指定せず、表示するエントリ数のカウントのみを指定します。次に、返された最後のエントリのキーをメモし、それを次のページの開始キーとして使用できます。この単純なフォームでは、あるページの最後のエントリが次のページの最初のエントリであるオーバーラップが発生します。これが望ましくない場合は、ページの最後のエントリを表示しないことは簡単です。
これを行う簡単な方法は、skipパラメーターを使用してページの開始ドキュメントを作成することですが、この方法は注意して使用する必要があります。 skipパラメータを使用すると、内部エンジンは繰り返し処理しているエントリを返さないようになります。これにより目的の動作が得られますが、ページの最初のドキュメントをキーで見つけるよりもはるかに時間がかかります。スキップされるドキュメントが多いほど、リクエストは遅くなります。
これは私がこれまでに思いついたものです-すべての投稿の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つの変数を取る
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();
});
});
}