Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

DynamoDB: How to perform conditional write to enforce unique Hash + Range key

I am using DynamoDB to store events. They are stored in 1 event table with a hash key 'Source ID' and a range key 'version'. Every time a new event occurs for a source, i want to add a new item with the source ID and an increased version nr.

Is it possible to specify a conditional write so that a duplicate item (same hash key and same range key) can never exist? And if so, how would you do this?

I have done this successfully for tables with just a Hash Key:

Map<String, ExpectedAttributeValue> expected = new HashMap<String, ExpectedAttributeValue>();
expected.put("key", new ExpectedAttributeValue().withExists(false));

But not sure how to handle hash + range keys....

like image 659
stikkos Avatar asked Oct 25 '12 18:10

stikkos


People also ask

Is DynamoDB hash key unique?

"Hash and Range Primary Key" means that a single row in DynamoDB has a unique primary key made up of both the hash and the range key. For example with a hash key of X and range key of Y, your primary key is effectively XY.

How do I create a unique constraint in DynamoDB?

To define a unique constraint for the username too, just add items with the type “username”. Also, by defining the rarer of the two parts of the key as the partition, you'll end up with more partitions, which is a best practice when working with DynamoDB.

Does Amazon DynamoDB support conditional operations?

Yes, like all the other database management systems, DynamoDB also supports all the conditional operators, User can specify a condition that is satisfied for a put, update, or delete operation to work on an item.

Does DynamoDB primary key need to be unique?

Primary key. When you create a table, in addition to the table name, you must specify the primary key of the table. The primary key uniquely identifies each item in the table, so that no two items can have the same key.


2 Answers

I don't know Java SDK well but you can specify "Exist=False" on both the range_key and the hash_key.

Maybe a better idea could be to use a timestamp instead of a version number ? Otherwise, there are also techniques to generate unique ids.

like image 50
yadutaf Avatar answered Sep 28 '22 08:09

yadutaf


I was trying to enforce a unique combination of hash and range keys and came across this post. I found that it didn't completely answer my question but certainly pointed me in the right direction. This is an attempt to tidy up the loose ends.

It seems that DynamoDB actually enforces a unique combination of hash and range key by design. I quote

"All items in the table must have a value for the primary key attribute and Amazon DynamoDB ensures that the value for that name is unique"

from http://aws.amazon.com/dynamodb/ under the section with the heading Primary Key.

In my own tests using putItem with the aws-sdk for nodejs I was able to post two identical items without generating an error. When I checked the database, only one item was actually inserted. It seems that the second call to putItem with the same hash and range key combination is treated like an update to the original item.

I too received the error "Cannot expect an attribute to have a specified value while expecting it to not exist" when I tried to set the exist=false option on the hash key and range key with the values set. To resolve this error, I removed the value under the expected hash and range key and it started to generate a validation error when I tried to insert the same key twice.

So, my insert command looks like this (will be different for Java, but hopefully you get the idea)

{     "TableName": "MyTableName",

 "Item"          :  {

                          "HashKeyFieldName": {

                                   "S": HashKeyValue

                          }, 

                          "RangeKeyFieldName": {

                                   "N": currentTime.getTime().toString()

                          },

                          "OtherField": {

                                   "N": "61404032632"

                          }

                      },

 "Expected":  {

                         "HashKeyFieldName"       : { "Exists" : false},
                         "RangeKeyFieldName"     : { "Exists" : false}

                    }

}

Whereas originally I was trying to do a conditional insert to check if there was a hash value and range value the same as what I was trying to insert, now I just need to check if the HashField and RangeField exist at all. If they exist, that means I am updating an item rather than inserting.

like image 27
Sudsy Avatar answered Sep 28 '22 10:09

Sudsy