DynamoDBMapper

ananthsrinivas
3 min readMay 1, 2019

--

We already discussed about the different ways to access Dynamodb programatically in the previous blog here. Today will take a look at using DynamodbMapper with examples.

Below is the DDB table model that we are going to use for today’s discussion,

DynamoDB Item —ProductCatalog

import com.amazonaws.services.dynamodbv2.datamodeling.DynamoDBAttribute;
import com.amazonaws.services.dynamodbv2.datamodeling.DynamoDBHashKey;
import com.amazonaws.services.dynamodbv2.datamodeling.DynamoDBRangeKey;
import com.amazonaws.services.dynamodbv2.datamodeling.DynamoDBTable;
import lombok.Data;

@Data
@DynamoDBTable(tableName="ProductCatalog")
public class ProductCatalog {

@DynamoDBHashKey(attributeName="productId")
private String productId;

@DynamoDBRangeKey(attributeName="lotNumber")
private long lotNumber;

@DynamoDBAttribute(attributeName="title")
private String title;

@DynamoDBAttribute(attributeName="bestByDate")
private long bestByDate;

@DynamoDBAttribute(attributeName="mfgDate")
private long mfgDate;
}

Below is the small accessor class to access this Dynamo db table,

DDB Access class

import com.amazonaws.services.dynamodbv2.AmazonDynamoDB;
import com.amazonaws.services.dynamodbv2.AmazonDynamoDBClientBuilder;
import com.amazonaws.services.dynamodbv2.datamodeling.DynamoDBMapper;
import com.amazonaws.services.dynamodbv2.datamodeling.DynamoDBQueryExpression;
import java.util.List;public class DDBAccess { private DynamoDBMapper ddbMapper =
new DynamoDBMapper((AmazonDynamoDB) AmazonDynamoDBClientBuilder.standard().build());
public ProductCatalog getItem(ProductCatalog item) {
return ddbMapper.load(ProductCatalog.class, item.getProductId(), item.getLotNumber());
}
public void saveItem(ProductCatalog item) {
ddbMapper.save(item);
}
public List<ProductCatalog> getItems(ProductCatalog item) {
return ddbMapper.query(ProductCatalog.class, new DynamoDBQueryExpression().withHashKeyValues(item));
}
}

Code Breakdown

Operation: Load (DDB Client GetItem equivalent)

// Using ddbMapper load operation to get the Itempublic ProductCatalog getItem(ProductCatalog item) {
return ddbMapper.load(ProductCatalog.class, item.getProductId(), item.getLotNumber());
}

Note: with load operation you will be able to load the item by providing both the hash and range keys for the table schema having hash and range keys.

Operation: Query

// Using query to get the itemspublic List<ProductCatalog> getItems(ProductCatalog item) {
return ddbMapper.query(ProductCatalog.class, new DynamoDBQueryExpression().withHashKeyValues(item));
}

As you can see in the above example, we can use DynamoDBQueryExpression and fetch the items based on the given Hash key itself. This will return all the items that are matching the Hash key.

Operation: Save

// Using query to get the itemspublic void saveItem(ProductCatalog item) {
ddbMapper.save(item);
}

As we saw in previous blog, save method is used to the record the item into ddb.

Note: even for update save method of ddb Mapper is used. Be cautious when passing the item to the save method (remove fields that you don’t want to get updated). You must construct the item object with Hash and Range keys by default and additional attributes that needs to be updated.

Key points:

  1. Load method needs hash and range key for retrieving an item if the table has hash and range keys.
  2. Query method let’s you use query expression and query the items by just giving the hash key
  3. Save method let’s you create and update the record as well.

Code to access Dynamo db table

I have written a small code and used the above DDBAccess class to create, get and query some items from the table. Full code is checked in here

package com.project.aws;

import lombok.extern.log4j.Log4j2;

import java.util.List;

@Log4j2
public class App
{
public static void main( String[] args ) {
DDBAccess ddbAccess = new DDBAccess();

// 1. Create an Item into DDB table.
ProductCatalog itemToRecord = createProductItem();
ddbAccess.saveItem(itemToRecord);

itemToRecord.setLotNumber(70005);
ddbAccess.saveItem(itemToRecord);

itemToRecord.setLotNumber(70003);
ddbAccess.saveItem(itemToRecord);

itemToRecord.setLotNumber(70004);
ddbAccess.saveItem(itemToRecord);

// 2. Fetch based on HashKey and RangeKey
ProductCatalog itemToFetchFromHashAndRangeKeys = createProductItemWithHashAndRangeKeys();
log.error("Item to fetch based on hashKey : {} - rangeKey : {}",
itemToFetchFromHashAndRangeKeys.getProductId(), itemToFetchFromHashAndRangeKeys.getLotNumber());
ProductCatalog item = ddbAccess.getItem(itemToFetchFromHashAndRangeKeys);
log.error("Product item fetched :{}", item);

// 3. Fetch item(s) based on HashKey
ProductCatalog itemToFetchFromHashKey = createProductItemWithHashKey();
log.error("Item to fetch based on hashKey : {}", itemToFetchFromHashKey.getProductId());
List<ProductCatalog> itemsFetched = ddbAccess.getItems(itemToFetchFromHashKey);
log.error("Items fetched :{}", itemsFetched);

}

private static ProductCatalog createProductItem() {
// Setting expiry time of the product as 3 months time from now.
ProductCatalog item = new ProductCatalog();
item.setProductId("AE9QFENAED");
item.setLotNumber(70002);
item.setTitle("Cosmetics");
item.setMfgDate(System.currentTimeMillis()/1000);
item.setBestByDate(System.currentTimeMillis()/1000 + 86400*90);
return item;
}

private static ProductCatalog createProductItemWithHashAndRangeKeys() {
ProductCatalog item = new ProductCatalog();
item.setProductId("AE9QFENAED");
item.setLotNumber(70001);
return item;
}

private static ProductCatalog createProductItemWithHashKey() {
ProductCatalog item = new ProductCatalog();
item.setProductId("AE9QFENAED");
return item;
}
}

Output

com.project.aws.App - Item to fetch based on hashKey : AE9QFENAED - rangeKey : 70001
com.project.aws.App - Product item fetched :ProductCatalog(productId=AE9QFENAED, lotNumber=70001, title=Cosmetics, bestByDate=1564286817, mfgDate=1556510817)
com.project.aws.App - Item to fetch based on hashKey : AE9QFENAED
com.project.aws.App - Items fetched :[
ProductCatalog(productId=AE9QFENAED, lotNumber=70001, title=Cosmetics, bestByDate=1564286817, mfgDate=1556510817), ProductCatalog(productId=AE9QFENAED, lotNumber=70002, title=Cosmetics, bestByDate=1564452669, mfgDate=1556676669), ProductCatalog(productId=AE9QFENAED, lotNumber=70003, title=Cosmetics, bestByDate=1564452669, mfgDate=1556676669), ProductCatalog(productId=AE9QFENAED, lotNumber=70004, title=Cosmetics, bestByDate=1564452669, mfgDate=1556676669), ProductCatalog(productId=AE9QFENAED, lotNumber=70005, title=Cosmetics, bestByDate=1564452669, mfgDate=1556676669)
]

Summary

Dynamo db mapper has a comprehensive list of methods to access the dynamo db table and saves lot of mapper code to be written otherwise.

The example code discussed above is present in the github. Feel free to check it out https://github.com/AnanthSrinivasan/DDBAccess. In the directory structure there is a file named DDB_template.yaml. I used something called cloud formation template to create the DDB table resource in discussion. I will talk about cloud formation and its uses in a separate blog.

Feel free to share your use cases with AWS components. Also please share/critique your comments about the blog.

--

--