AWS Developer Tools Blog

DynamoDB XSpec API

One of the most powerful tools for accessing Amazon DynamoDB is the use of a DynamoDB domain-specific language (DSL) called expressions. If you look closely, you will find the support of DynamoDB expressions everywhere. For instance, you can access the attributes of an item using projection expressions. You can query or scan items using filter expressions and key condition expressions. Likewise, you can specify the details of updating an item using update expressions and condition expressions.

Why the need for expressions? Not only can you use DynamoDB expressions to perform typical operations such as PutItem, GetItem, Query, etc., you can also use expressions to specify arbitrarily complex operations and conditions that are otherwise not possible with the regular APIs. This can best be illustrated with examples.

But first, with the latest release 1.9.34 of the AWS SDK of Java, we are excited to announce the beta release of the Expression Specification (XSpec) API, which makes it easy to build and make use of expressions.

Let’s take a look at the code snippet copied from the earlier blog, Introducing DynamoDB Document API (Part 1). This is what the code looks like to perform a conditional update without the use of expressions:

UpdateItemOutcome outcome = table.updateItem(new UpdateItemSpec()
    .withReturnValues(ReturnValue.ALL_NEW)
    .withPrimaryKey("GameId", "abc")
    .withAttributeUpdate(
        new AttributeUpdate("Player1-Position").addNumeric(1))
    .withExpected(
        new Expected("Player1-Position").lt(20),
        new Expected("Player2-Position").lt(20),
        new Expected("Status").eq("IN_PROGRESS"))); 

This is all well and good. But what if you need to specify a more complex condition such as the use of disjunction or nested conditions? This is where you will find the DynamoDB XSpec API handy. For example, suppose you want to specify a nested or-condition, together with a function that checks if a specific attribute exists. Here is how you can do that using the DynamodB XSpec API:

import static com.amazonaws.services.dynamodbv2.xspec.ExpressionSpecBuilder.*;
...
UpdateItemOutcome outcome = table.updateItem(new UpdateItemSpec()
    .withReturnValues(ReturnValue.ALL_NEW)
    .withPrimaryKey("GameId", "abc")
    .withExpressionSpec(new ExpressionSpecBuilder()
        .addUpdate(N("Player1-Position").add(1))
        .withCondition(
                  N("Player1-Position").lt(20)
            .and( N("Player2-Position").lt(20) )
            .and( S("Status").eq("IN_PROGRESS")
                .or( attribute_not_exists("Status") )))
        .buildForUpdate()));

Or perhaps you want to specify an arbitrarily complex condition in a Scan operation. Here is an example:

import static com.amazonaws.services.dynamodbv2.xspec.ExpressionSpecBuilder.*;
...
ScanExpressionSpec xspec = new ExpressionSpecBuilder()
    .withCondition(N("Player1-Position").between(10, 20)
        .and( S("Status").in("IN_PROGRESS", "IDLE")
              .or( attribute_not_exists("Status") )))
    .buildForScan();

for (Item item: table.scan(xspec))
    System.out.println(item.toJSONPretty());

It’s worth pointing out that the only entry point to the DynamoDB XSpec API is the ExpressionSpecBuilder. We also recommend to always specify the static imports of its methods as demonstrated above.

In summary, the DynamoDB expression language allows arbitrarily complex conditions and operations to be specified, whereas the DynamoDB XSpec API makes it easy to harness the full power of this language.

Hope you find this useful. Don’t forget to download the latest AWS SDK for Java and give it a spin. Let us know what you think!