Reputation: 1623
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).
Upvotes: 2
Views: 2044
Reputation: 13117
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)
Upvotes: 4