DynamoDB insert once


DynamoDB

Amazon DynamoDB is a managed NoSQL database service with neat latency guarantees at large scale. Practical usage DynamoDB requires care in modelling and querying

API

Documentation for DynamoDB is extensive but also confusing. There are multiple ways to program for Dynamo.

The Object Persistence Interface feels most natural to use as a Java programmer. The DynamoDBMapper class implements the DynamoDB object persistence interface providing methods like save() and load(). The DynamoDBMapper acts as a wrapper around the low-level client (AmazonDynamoDB).

Low level interfaces map closer to the DynamoDB REST API payload. This API requires more work from the programmer.

Preventing Overwrites of an Existing Item

Items are identified by a primary key. If multiple PutItem operations are done for the same key, then data will be overwritten. To prevent this, documentation states that a condition expression needs to be used. This will allow the write to proceed only if the item in question does not already have the same key-

aws dynamodb put-item \
    --table-name ProductCatalog \
    --item file://item.json \
    --condition-expression "attribute_not_exists(Id)"

However this API is not present in the DynamoDBMapper interface!

The DynamoDBMapper uses legacy Condition Operators instead. The equivalent operation can be done by using Exists like-

aws dynamodb put-item \
    --table-name ProductCatalog \
    --item '{
      "Id": {"N":"500"},
        "Title": {"S":"Book 500 Title"}
    }' \
    --expected '{
        "Id": { "Exists": false } 
    }'

And finally to use this with DynamoDBMapper, sample code would look like-

// Set expected false for an attribute
ExpectedAttributeValue expectedAttributeValue = new ExpectedAttributeValue();
expectedAttributeValue.setExists(Boolean.FALSE);

// Map the id field to the ExpectedAttributeValue
Map<String, ExpectedAttributeValue> expectedAttributes = new HashMap<>();
expectedAttributes.put("id", expectedAttributeValue);

// Use the attributes within a DynamoDBSaveExpression
DynamoDBSaveExpression saveExpression = new DynamoDBSaveExpression();
saveExpression.setExpected(expectedAttributes);

// Save to dynamoDBMapper using the saveExpression
dynamoDBMapper.save(item, saveExpression);

The code above will throw a ConditionalCheckFailedException if there is an existing item already.