Simon PainterSomewhere to keep things

aws php sdk & DynamoDB

I am working on a project that requires me to store publishers and subscribers in a DynamoDB table. As both elements are stored as integers and as I only ever need to find out the subscribers of a publisher (and not the publisher that a subscriber is subscribed to) it’s possible to use a list attribute, for the publisher object, containing the subscribers. I wanted to be able to insert a new subscriber as a unique entity in the list without first reading the list – this is because of the way DynamoDB is charged with reads and writes. After extensive research it wasn’t clear how to do this but I managed to piece it together and wanted to share it.

Firstly we set up some values. The attribute is called subscribers so that is placed in #subscribers and then the value we want to insert is placed in two formats – once as a single entry in a list/array and then again as a single value. Note that in this case it’s a number so there are no enclosing quotes. We shall get to why we need it in two formats in a bit. We also create an empty list which is stored as :empty_list

$ExpressionAttributeNames = [
     "#subscribers" => "subscribers"
];

$ExpressionAttributeValues = $marshaler->marshalJson('
{
     ":subscriber" : ['.$subscriber.'],
     ":subscriberNum" : '.$subscriber.',
     ":empty_list" :[]
}
');

Next we need an update expression. The update expression sets the attribute held in the value #subscribers to be appended with the value :subscriber. Note that :subscriber is a list/array because you have to append a list to a list.

If the attribute #subscribers doesn’t exist already then it is created with an empty list and then the list containing the new element is appended.

$UpdateExpression = "SET #subscribers = list_append(if_not_exists(#subscribers, :empty_list), :subscriber)";

This in itself would add the value repeatedly, which is not the desired result; we want the values to be unique. We can achieve this using a Condition Expression. If the condition matches as true then the value is inserted however if it is not true then an exception is raised (which can be caught and dealt with). The expression below took a little time to figure out because you have to use the number value to search for rather than the array of one value that you use for the appending. This is the reason we have to store the number value once as a number and once as a single value in an array.

$ConditionExpression = "
     NOT contains (#subscribers,:subscriberNum)
";

The full gist is here.

Tags: , , , ,

Comments are currently closed.