Here are my use cases: I have a Dynamo table with a hash + range key. When I put new items in the table, I want to do a uniqueness check. Sometimes I want to guarantee that the hash is unique (ignoring the range). Other times I want to allow duplicate hashes, but guarantee that the hash and range combination is unique. How can I accomplish this?
I experimented with attribute_not_exists. It seems to handle the second case, where it checks the hash + key combination. Here's a PHP sample:
$client->putItem(array( 'TableName' => 'test', 'Item' => array( 'hash' => array('S' => 'abcdefg'), 'range' => array('S' => 'some other value'), 'whatever' => array('N' => 233) ), 'ConditionExpression' => 'attribute_not_exists(hash)' ));
Oddly, it doesn't seem to matter if I use attribute_not_exists(hash)
or attribute_not_exists(range)
. They both seem to do exactly the same thing. Is this how it's supposed to work?
Any idea how to handle the case where I only want to check hash
for uniqueness?
You can't. All items in DynamoDB are indexed by either their hash
or hash
+range
(depending on your table). A single hash key can have multiple range keys.
Say for example you have the following items:
hash=A,range=1
hash=A,range=2
You have 2 possible outcomes:
If you try to put an item with hash=A,range=3
and attribute_not_exists(hash)
, you will get true
. There is no item with hash=A,range=3
that exists that has an attribute named hash
. If instead you use attribute_not_exists(range)
there is no item with hash=A,range=3
that exists that has an attribute named range
so you will also get true
.
If you try to put an item with hash=A,range=1
and attribute_not_exists(hash)
, you will get false
there is an item with hash=A,range=3
that exists that has an attribute named hash
. If instead you use attribute_not_exists(range)
there is an item with hash=A,range=3
that exists that has an attribute named range
.
What this attribute_not_exist
is effectively doing for both of these is a does the item not exist check.
More in depth explanation:
- Every item has both a
hash
and a range
key - You are making a
PutItem
request and must provide both the hash
and range
- You are providing a
ConditionExpression
with attribute_not_exists
on either the hash
or range
key
This means that one of two things will happen:
- The
hash
+range
pair exists in the database. attribute_not_exists(hash)
must be true
attribute_not_exists(range)
must be true
- The
hash
+range
pair does not exist in the database. attribute_not_exists(hash)
must be false
attribute_not_exists(range)
must be false
In both cases, you get the same result regardless of whether you put it on the hash or the range key. You are effectively checking does an item with this hash+range key already exist.
You can use AND operation if your table has hash and range
'ConditionExpression' => 'attribute_not_exists(hash) AND attribute_not_exists(range)'