初級読了 3 分

DynamoDB のページネーション

DynamoDB は「すべての」結果を1回の呼び出しで返すことはありません。QueryScan は最大 1 MB のデータを返し、そこから再開するための LastEvaluatedKey を渡します。ページネーションを正しく行うとは、カウンターではなくそのキーでループすることです。

DynamoDB のページネーションはどう機能しますか?

QueryScan は1回の呼び出しで最大 1 MB を返し、LastEvaluatedKey を返却します。ページをめくるには、そのキーを次の呼び出しの ExclusiveStartKey として渡し、DynamoDB がキーを返さなくなるまでループします。ページ番号も、総件数もありません。Limit は返される件数ではなく、評価される件数の上限です。

let key;
do {
  const out = await client.send(new QueryCommand({...params, ExclusiveStartKey: key}));
  process(out.Items);
  key = out.LastEvaluatedKey;
} while (key);

LastEvaluatedKeyundefined になったら、終端に達しています。次のスライスを取得するには、それを ExclusiveStartKey として渡し返します。

制御フローは、キーが無いときだけ抜ける単一のループです。

presentabsentQuery / ScanProcess ItemsLastEvaluatedKey?Set ExclusiveStartKeyDone

各パスは、返されたキーから再開するか、停止するかのいずれかです。カウンターは存在しません。

Limit はページサイズではない

Limit は DynamoDB が評価するアイテム数の上限であって、FilterExpression 適用後に返す数ではありません。フィルタの背後にある Limit: 25 のクエリは、3件を返しつつ LastEvaluatedKey を渡してくることがあります。ページが短く見えても、キーが空になるまでページングを続けなければなりません。空でない LastEvaluatedKey も、より多くの一致するアイテムがあることを約束しません。終端に達したことを証明するのは、キーが無いことだけです。

SDK にページングさせる

どちらの SDK も上記のループをラップしているので、ページを直接反復できます。

// AWS SDK for JavaScript v3
import {paginateQuery} from '@aws-sdk/lib-dynamodb';
for await (const page of paginateQuery({client}, params)) {
  process(page.Items);
}
# boto3
paginator = client.get_paginator('query')
for page in paginator.paginate(**params):
    process(page['Items'])

ページ番号はない

DynamoDB には総件数もランダムなページアクセスもありません。カーソルを再生し直さずに「7ページ目」に飛んだり前のページに戻ったりはできません。UI は無限スクロール/「もっと読み込む」を中心に設計し、番号付きページにはしないでください。(Select: 'COUNT' のクエリでも、件数を数えるために一致した全アイテムを読み取り、課金されます。)

API 向けのステートレスなカーソル

LastEvaluatedKey は最後のアイテムのキー属性にすぎません。それを Base64 エンコードし、不透明な nextToken としてクライアントに渡します。次のリクエストでそれを ExclusiveStartKey にデコードして戻します。サーバー側のカーソル状態は不要です。

そのトークンは DynamoDB-JSON です。DynamoDB-JSON コンバーターで目視したり手で組み立てたりできます。そしてScanを回避するためにページングしているなら、それはたいていインデックスを追加すべきシグナルです。

ループを書くこと自体を飛ばすには、クエリビルダーが完全な Query/Scan リクエストを組み立て、実行可能な SDK v3、CLI、boto3 のプログラムを — ページネーションループ込みで — 出力します。

DynoTable を試すと、カーソルを追跡した状態で、クエリ結果をビジュアルにページ送りできます。

更新日