'Does dynamodb supports atomic counter on SET operation if value is not exists?
I have a use case where I need to store how many people view the blog post in DynamoDB.
Lets' say I have a table like below
| blogId | Total Views. |
|---|---|
| 1 | 100 |
Now when a user views a new blog with ID 2 I have to store that in the table. I can do the following to achieve that:
isBlogExists = dynamodbMapper.get(BlogViews,{blogId: 2})
if (isBlogExists){
dynamodbMapper.set("totalViews", new MathematicalExpression("totalViews", "+", 1))
} else{
dynamodbMapper.set("totalViews", 1)
}
Unfortunately it ends up in race condition so I planned to use the SET operation like this
dynamodbMapper.set("totalViews", new MathematicalExpression("totalViews", "+", 1))
Since this item doesn't have the totalViews attribute, I am getting a error like
No item with the key found in Table.
So does DynamoDB doesn't support incrementing numeric values on key which doesn't exist?
I could use the ADD operation but DynamoDB recommends to use SET over ADD (source).
Solution 1:[1]
DynamoDB offers the straightforward way of using ADD in the UpdateExpression, but AWS generally recommends going with SET instead:
Note
In general, we recommend using SET rather than ADD.
I don't see why and they don't elaborate on that. If you want to follow their guidance, here is what you can do.
The straightforward SET attr = attr + 1 falls short in some cases because it requires the attribute to exist already. The ADD expression assumes a default of 0 if that's not the case, SET doesn't.
Fortunately, we can create a default for non-existent attributes using the if_not_exists function. Here's an example of how to use it. It assumes a table called pk-only with only a partition key called PK of type string.
import boto3
TABLE_NAME = "pk-only"
TABLE_RESOURCE = boto3.resource("dynamodb").Table(TABLE_NAME)
def main():
TABLE_RESOURCE.update_item(
Key={"PK": "some_item"},
UpdateExpression="SET #att = if_not_exists(#att, :start_value) + :inc",
ExpressionAttributeNames={
"#att": "counter"
},
ExpressionAttributeValues={
":inc": 1,
":start_value": 0
}
)
if __name__ == "__main__":
main()
(This is an example in Python, but you should be able to adapt it to your Javascript code quite easily)
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
| Solution | Source |
|---|---|
| Solution 1 | Maurice |
