입문3분 분량

DynamoDB의 페이지네이션

DynamoDB는 한 번의 호출로 "모든" 결과를 반환하지 않습니다. QueryScan은 최대 1 MB의 데이터를 반환한 뒤, 이어서 시작할 수 있는 LastEvaluatedKey를 건네줍니다. 페이지네이션을 제대로 하려면 카운터가 아니라 그 키를 기준으로 루프를 돌아야 합니다.

루프

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로 디코딩하세요. 서버 측 커서 상태가 없습니다.

그 token은 DynamoDB-JSON입니다 — DynamoDB-JSON 변환기로 직접 살펴보거나 손수 만들어 보세요. 그리고 Scan을 우회하려고 페이지를 넘기고 있다면, 보통 인덱스를 추가하라는 신호입니다.

DynoTable을 사용해 커서를 대신 추적하면서 쿼리 결과를 시각적으로 페이지 넘겨 보세요.

업데이트됨