I have a DynamoDB table defined as follows:
Partition key: id (string)
Sort key: ruleId (string)
Example item:
{ "id": "123", "ruleId": "abc" }
What I want is SQL-like behavior:
INSERT INTO table (id, ruleId) VALUES ('123', 'abc')
ON CONFLICT DO NOTHING;
In other words:
Allow multiple rows with the same id but different ruleIds (e.g. (123, abc) and (123, def)).
Prevent inserting the same (id, ruleId) pair twice and perform some client side if the put fails. I am using the ConditionFailedException to track whether an item is inputted or not.
Table schema (current)
Right now, my table has:
Partition key: id (string)
Sort key: ruleId (string)
Example item:
{
"id": "123",
"ruleId": "abc"
}
What I’ve tried
Using the AWS SDK PutItem, I’ve experimented with condition expressions to enforce uniqueness:
ConditionExpression: "attribute_not_exists(id) AND attribute_not_exists(ruleId)"
This rejects inserts whenever the same id already exists (even if it’s a different ruleId).
ConditionExpression: "attribute_not_exists(id)"
This seems to reject new ruleIds for the same id.
ConditionExpression: "attribute_not_exists(ruleId)"
This works sometimes, but I’m not sure it’s the correct way to enforce uniqueness of (id, ruleId) pairs.
My confusion
Do I have to choose only one partition key, or can both id and ruleId be part of the key?
If I stick with (id, ruleId) as the composite primary key (partition key + sort key), what’s the correct condition expression to prevent overwriting an existing pair but allow new combinations?
What’s the best way to implement SQL-like behavior where the insert returns a boolean (or the item) to indicate whether the row was newly inserted or already existed?
attribute_not_exists(id)andattribute_not_exists(ruleId)really mean. They're evaluates not against the table, but against a single document, which is defined by the(id, ruleId)pair. Since that document either does or doesn't exist, both expressions always have the same truth-value. See this answer for more.