Front-End Web & Mobile

Using Amazon DynamoDB Document API with AWS Mobile SDK for Android – Part 1

The AWS Mobile SDK for Android helps developers write mobile apps by providing simplified APIs for using AWS services, such as Amazon Cognito and Amazon DynamoDB. In the past, to access data, you needed to use the DynamoDB Object Mapper (or use the service APIs). You then had to define a model within your mobile code that mirrors the model defined in the table for DynamoDB. This meant more code to write and test. With v2.4.4 of the SDK, we are introducing a new feature, which we call the Document API. With the Document API, you no longer need to use the DynamoDB Object Mapper; instead, you access individual fields within data objects directly.

What is the difference between the Object Mapper and the Document API?

The Document API provides a simplified interface to access the NoSQL data that is returned by DynamoDB. You no longer need to update schema or map the table properties to class members. The Document API provides new data types to assist in the serialization and deserialization process. The DynamoDB Object Mapper maps client-side model classes to DynamoDB tables.

Both APIs provide methods to perform create / update / delete (CRUD) operations and execute queries against the DynamoDB tables. The difference between the two APIs is in how the data is represented as you manipulate it within your mobile app.  This enables you to select the API that you feel is better for your situation. You can even mix and match. For example, you can use the Object Mapper for data in one table, and use the Document API for data in another table.

Working with the Document Object

When working with the Document API, you primarily work with a Document. A Document is the container for the data returned from or pushed to the Amazon DynamoDB database.

You can convert between JSON and Document objects. However, you will lose fidelity when converting from a Document object to JSON. This is because not all data types that can be stored in DynamoDB can be represented in JSON. Use Document.fromJson() and Document.toJson() to perform the conversion. For example:

Document myDocumentObject = Document.fromJson(myJsonString);
String myJsonString = Document.toJson(myDocumentObject);

The Document object accepts standard JSON types, like string, number, or Boolean:

Document doc = new Document();
doc.put(“stringField”, “value”);
doc.put(“numberField”, 2.0F);
doc.put(“booleanField”, true);

The Document object also accepts JSON arrays (represented as a set of items) and JSON maps (represented as another Document):

// An unordered list
Set<String> coll = new HashSet<String>();
coll.add(“string1”);
coll.add(“string2”);
doc.put(“arrayField”, coll);

// A key-value map
Document name = new Document();
name.put(“first”, “Adrian”);
name.put(“last”, “Hall”);
doc.put(“name”, name);

The Document object also accepts Amazon DynamoDB types, such as binary data, null, and ordered lists:

//null field
doc.put(“nullField”, DynamoDbNull.NULL);

// Binary Data
ByteBuffer buffer = new ByteBuffer();

// Populate the buffer with binary data
doc.put(“binaryField”, new Primitive(buffer));

// An Ordered List
DynamoDbList ddl = new DynamoDbList();
ddl.add(“string1”);
ddl.add(“string2”);
doc.put(“orderedList”, ddl);

You can access data within a Document object using the document path. For example:

String stringField = doc.get(“stringField”);
String firstName = doc.get(“name.first”);

If you do not know which data type is being returned, use the DynamoDbEntry type, and then compare it against the known types:

DynamoDBEntry entry = doc.get(“orderedList”);
If (entry instanceof DynamoDBList) {
    dynamoDBList list = entry.asDynamoDBList();
    for (Iterator I = list.iterator(); i.hasNext(); ) {
        DynamoDBEntry listEntry = (DynamoDBEntry)i.next();
    }
}

You can also use entry.asString(), entry.asNumber(), etc. to convert to more primitive types.

Handling Data with the Document API

Document objects are used as the unit of transfer between your mobile app and Amazon DynamoDB. Each of the CRUD operations within the Document API either accepts or returns a Document object. First, create an Amazon DynamoDB client, then get a reference to the DynamoDB table:

DynamoDBClient client = new DynamoDBClient(awsCredentialProvider, config);
Table myTable = Table.loadTable(client, “MyTable”);

Once you have a reference to the table, you can use putItem(), getItem(), updateItem() or deleteItem() to perform CRUD (create, read, update, delete) operations. For example, if you know the key of the item that you want to retrieve, you can use this key to retrieve the document, obtain the text content, and assign it to an Android control:

Document retrievedDoc = myTable.getItem(new Primitive(“key”));
myTextView.setText(retrievedDoc.get(“stringField”).asString());

If the user has changed the text, you can update the document as follows:

retrievedDoc.set(“stringField”, myTextView.getText());
Document updatedDoc = myTable.updateItem(retrievedDoc);

You can also query for data using the Document API. For example, to find all Document objects where the Age field is greater than 5:

final Expression expression = new Expression();
expression.setExpressionStatement("Age > :age");
expression.withExpressionAttibuteValues(":age", new Primitive(5));
Search searchResult = table.scan(expression);
List<Document> documents = searchResult.getAllResults();

The table.scan() method performs a query across all fields in the table, which is probably not the most optimal method for querying the table. If you have a partition key called userId (which contains the user’s ID), then you can run queries across a single partition using the table.query() method:

final Expression expression = new Expression();
expression.setExpressionStatement("Tag = :tag");
expression.withExpressionAttibuteValues(":tag", new Primitive(“sports”));

Search searchResult = table.query(new Primitive(“myUser”), expression);
List<Document> documents = searchResult.getAllResults();

This method will have better performance because DynamoDB is scanning fewer records.

Document API limitations

The DynamoDB Document API does not currently support:

  1. Data types such as S3Link, Date, Calendar, etc.
  2. Batch operations.
  3. Conditional expressions.

The Document API is currently in beta and we would like to hear about the use cases you would like us to support. You can leave your feedback and issues on our forums and GitHub.

In the second part of this blog, we will describe how to integrate the Document API into a real Android app and provide a sample app that shows the Document API in action.