Pagination with dynamodb

Pagination with dynamodb

Sage Huynh

Out of the box pagination DynamoDB provides

Amazon DynamoDB documentation says that DynamoDB paginates the results from scan/query operations. With pagination, the scan results are divided into pages of data that are 1 MB in size (or less). An application processes the first page of results, then the second page, and so on.

A single scan will only return a result set that fits within the 1 MB size limit. To determine whether there are more results, and to retrieve them one page at a time, your application should do the following:

  1. Examine the Scan result:
  • If the result contains a LastEvaluatedKey element, proceed to step 2.
  • If there is no LastEvaluatedKey in the results, then you are done. There are no more items to be retrieved.
  1. Construct a new Scan request, with the same parameters as the previous one — but this time, take the LastEvaluatedKey value from step 1 and use it as the ExclusiveStartKey parameter in the new Scan request.
  2. Run the new Scan request.

How pagination is done?

There are two approaches for the pagination to be done.

1st Approach — using scan

  • On the webpage where pagination is supported, the browser sends the LastEvaluatedKey to the server.
  • To access the first page, browser sends the LastEvaluatedKey as undefined. With this undefined key, server sends the first page data and also sends the LastEvaluatedKey for the next page.
  • To access the next page, the browser sends back the LastEvaluatedKey and the same procedure continues.
const async = require("async");
const _ = require("underscore");
const AWS = require("aws-sdk");
AWS.config.update({ region: 'ap-southeast-1' });

const docClient = new AWS.DynamoDB.DocumentClient();

var startKey = [];
var results = [];
var pages = 0;
async.doWhilst(
    (callback)=>{
        let params = {
            TableName: 'td_notes_test',
            Limit: 3
        };

        if(!_.isEmpty(startKey)) {
            params.ExclusiveStartKey = startKey;
        }

        docClient.scan(params, (err, data)=>{
            if(err) {
                console.log(err);
                callback(err, {});
            } else {
                if(typeof data.LastEvaluatedKey !== 'undefined') {
                    startKey = data.LastEvaluatedKey;
                } else {
                    startKey = [];
                }

                if(!_.isEmpty(data.Items)){
                    results = _.union(results, data.Items);
                }

                pages++;

                callback(null, results);
            }
        });
    },

    ()=>{
        if(_.isEmpty(startKey)) {
            return false;
        } else {
            return true;
        }
    },

    (err, data) => {
        if(err) {
            console.log(err);
        } else {
            console.log(data);
            console.log("Item Count", data.length);
            console.log("Pages", pages);
        }
    }
);

2nd approach — using Query

In case we want pagination with particular attribute then query with particular Partition key with the below method.

const AWS = require("aws-sdk");
AWS.config.update({ region: "ap-southeast-1" });
const TABLE_NAME = "write your table name";

const docClient = new AWS.DynamoDB.DocumentClient({
  sslEnabled: false,
  paramValidation: false,
  convertResponseTypes: false,
  convertEmptyValues: true,
});

let paginationDB = async () => {
  
   let queryParams = {
     TableName: TABLE_NAME,
     KeyConditionExpression: "#PK =  :PK",//Enter partitionKey 
     ExpressionAttributeNames: {
       "#PK": "id",// Enter partitionKey name
    },
     ExpressionAttributeValues: {
       ":PK": "123456", // Enter partitionKey value
    },
  };
  let result = [];
  let items;
  do {
    items = await docClient.query(queryParams).promise();
    items.Items.forEach((item) => result.push(item));
    queryParams.ExclusiveStartKey = items.LastEvaluatedKey;
  } while (typeof items.LastEvaluatedKey != "undefined");
     console.log("result", result);
     console.info("Available count size:", result.length);
};

paginationDB()
  .then((res) => {
    console.log(res);
  })
  .catch((err) => {
    console.log(err);
  });

That's it! Thank you for reading!