简体   繁体   中英

Pagination in Dynamo db while scan operation

I want to scan my Dynamo db table with pagination applied to it. In my request I want to send the number from where I want pagination to get start. Say, eg I am sending request with start = 3 and limit = 10, where start is I want scan to start with third item in the table and limit is upto 10 items. Limit however I can implement with .withLimit() method(I am using java). I followed this aws document. Following is the code of what I want to achieve:

<Map<String, AttributeValue>> mapList = new ArrayList<>();
      AmazonDynamoDB client =AmazonDynamoDBClientBuilder.standard().build();

      Gson gson = new GsonBuilder().serializeNulls().create();

      Map<String, AttributeValue> expressionAttributeValues = new 
      HashMap<String,AttributeValue>(); 
      expressionAttributeValues.put(":name",
      newAttributeValue().withS(name));

      List<ResponseDomain> domainList = new ArrayList<>(); 
      ResponseDomain responseDomain = null;

      //lastKeyEvaluated = start
      Map<String, AttributeValue> lastKeyEvaluated = null; 
      do { 
      ScanRequest scanRequest = new 
      ScanRequest().withTableName(STUDENT_TABLE)
      .withProjectionExpression("studentId, studentName")
      .withFilterExpression("begins_with(studentName, :name)")
      .withExpressionAttributeValues(expressionAttributeValues).
      withExclusiveStartKey(lastKeyEvaluated);

      ScanResult result = client.scan(scanRequest);

      for (Map<String, AttributeValue> item : result.getItems()) { 
      responseDomain = gson.fromJson(gson.toJson(item), 
      ResponseDomain.class); 
      domainList.add(responseDomain);


      } lastKeyEvaluated = result.getLastEvaluatedKey(); 
      } while (lastKeyEvaluated!= null); 
      //lastKeyEvaluated = size

      return responseDomain;

In the above code I am stuck at 3 places:

  1. How can I set lastKeyEvaluated as my start value ie 3
  2. In the while condition how can I specify my limit ie 10
  3. When I try to map item from Json to my domain class, I encounter error.

Am I misinterpreting the concept of pagination in dynamodb or doing something wrong in the code. Any guidance will be highly appreciated as I am a newbie.

  1. You can only start reading from some place by the ExclusiveStartKey . This key is the primary key of your table. If you know your item key, you can use it like this (eg your table primary key is studentId ):

     Map<String, AttributeValue> lastKeyEvaluated = new HashMap<String,AttributeValue>(); lastKeyEvaluated.put("studentId", new AttributeValue(STUDENTID)); 
  2. When you specify the limit = N in dynamo you are setting that it should only read N items from the table. Any filtering is applied after the N items have been read. See Limiting the Number of Items in the Result Set . That might leave you with less results than expected. So you could create a variable in your code to send requests until you hit your expected limit and cutoff the extra results.

     int N = 10; List<Map<String, AttributeValue>> itemsList = new ArrayList<>(); do { // scanRequest.withLimit(N) ... itemList.addAll(result.getItems()); if(itemsList.size() >= N) { itemsList = itemsList.subList(0, N); break; } } while (lastKeyEvaluated != null && itemsList.size() < N); // process the itemsList 
  3. Dynamo uses it's own json structure. See Dynamo response syntax . You can get the value of an attribute the way you stored it in dynamo. If studentId is a string then it could be something like this:

     for (Map<String, AttributeValue> item : result.getItems()) { responseDomain = new ResponseDomain(); responseDomain.setId(item.get("studentId").getS()); domainList.add(responseDomain); } 

Pagination doesn't quite work the way you are thinking.

Use ScanRequest.withLimit(X) to choose the number of items in each page of results . For example, setting ScanRequest.withLimit(10) means that each page of results you get will have 10 items in it.

The lastKeyEvaluated is not a number of a page, it is the actual key of an item in the table. Specifically it is the key of the last item in the last set of results you retrieved.

Think about it like this. Imagine your results are:

Dog
Chicken
Cat
Cow
Rhino
Buffalo

Now lets say I did ScanRequest.withLimit(2) and lastKeyEvaluated = null, so each page of results has 2 items and I will retrive the first page of results. My first scan returns

Dog
Chicken

And

lastKeyEvaluated = result.getLastEvaluatedKey();

Returns

Chicken

And now to get the next page of results I would use ScanRequest.withExclusiveStartKey(Chicken). And the next set of results would be

Cat
Cow

Your code above uses a do/while loop to retrieve every page of results and print it out. Most likely you will want to remove that do/while loop so that you can handle one page at a time, then retrieve the next page when you are ready.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM