Create entity if not exists in DynamoDB from Java

In my current project we’re using the Amazon DynamoDB database in some of our bounded contexts. One use case that we have is to create an entity only if it doesn’t previously exists (i.e. don’t overwrite the previous entity if the hash key is already defined). Of course this has to be an atomic operation. When you know how to do this it’s not hard but I still think an example would be pretty nice. First off all I couldn’t find I way to do this using the high-level Java object mapping API (DynamoDBMapper) so I had to revert to using the low-level API instead (if you know a way to do it please let me know in the comments). The trick is to use the Exists parameter when sending the PutItem request. Setting it to false will cause the Amazon Java API to throw a ConditionalCheckFailedException when the entity already exists. Here’s a full example:

Note that I’m using Guava’s ImmutableMap builder in the example to be able to create HashMap’s in a more fluent way.

That’s it!

This Post Has 9 Comments

  1. Hi.

    I don’t know which version of the DynamoDBMapper you used, but the current version 1.7.5 can handle the same request.

    Example:

    [code]
    User newUser = new User();
    newUser.setUsername(username);
    newUser.setPassword(password);

    DynamoDBSaveExpression saveExpr = new DynamoDBSaveExpression();
    saveExpr.setExpected(new ImmutableMap.Builder()
    .put(“username”, new ExpectedAttributeValue(false)).build());

    dynamoDBMapper.save(newUser, saveExpr);
    [/code]

  2. I don’t remember which version I used back then but it’s nice to see that it’s now supported.

    Thanks for the tip.

  3. Regarding Jannik’s reply….I couldn’t find how to do it with the new DynamoDbMapper. Example is also missing from the comment. Could you post what documentation you are referring to or maybe just show the example. Thanks.

  4. I was looking to use this technique to act as a locking mechanism for files in S3. So, if something needs to write to a certain file, it will do this conditional put and if it fails because the item already exists, it means something else has the file lock and it backs off before doing a retry.

    Obviously, it’s crucial that the current lock holder always releases the lock when it’s done, but I was wondering if this mechanism is safe for this use case. Even if my DDB table is strongly consistent, does the possibility of a race condition still exist?

    1. This may be a little too late, but you could always use versioning on your lock to prevent race conditions. With a consistent read, it works.

  5. Hello,

    For the ones interested in a solution using DynamoDBMapper I could successfully use a DynamoDBSaveExpression:

    public boolean saveIfDoesNotExist(SingleJobLock singleJobLock) {
    DynamoDBSaveExpression saveExpression = new DynamoDBSaveExpression();
    Map expected = new HashMap();
    expected.put(“jobType”, new ExpectedAttributeValue(false));
    expected.put(“jobTime”, new ExpectedAttributeValue(false));
    saveExpression.setExpected(expected);

    try {
    dynamoDBMapper.save(singleJobLock, saveExpression);
    } catch (ConditionalCheckFailedException e) {
    return false;
    }

    return true;
    }

    In this case if a SingleJobLock is already defined with the same ‘jobType’ and ‘jobTime’ attributes, a ConditionalCheckFailedException will be thrown.

    1. Yes, that works. Thanks Arnaud.

  6. FYI: Now, without any low-level APIs and using DynamoDBTableMapper, you can get the expected results in a single line:

    // DynamoDBTableMapper table = dynamoDBMapper.newTableMapper(MappedObject.class);

    table.saveIfNotExists(mappedObjectInstance);

    This method will throw ConditionalExpressionFailedException if the hash-key (and if applicable range-key) already exists.

  7. if I want to check if the value of the filed exists before saving, but not by cache-key?

Leave a Reply

Close Menu