46

Let's say that I am storing records with following structure in DynamoDB:

{    
    "id": "57cf5b43-f9ec-4796-9de6-6a50f556cfd8",
    "created_at": "2015-09-18T13:27:00+12:00",
    "count": 3
}

Now, is it possible to achieve the following in one request:

  • if the record with given id doesn't exist it should be created with count = 1
  • if the record for that id exists the counter is being updated.

Currently I'm doing a query to check if the record exist and depending on the result I do a put or an update. It would be nice to fold that into a single operation.

Piotr Zurek
  • 2,800
  • 2
  • 24
  • 32
  • This wouldn't work if you also wanted to upsert `id`, if `id` were a key to your table. https://stackoverflow.com/questions/30296850/is-it-possible-to-change-value-of-range-key-in-dynamodb-table#30314563 ... Useful for those who attempted to do what I just tried, by adapting your solution. – user3773048 Nov 24 '21 at 18:36

2 Answers2

41

What I didn't mention in my question was that I wanted the count go up for subsequent events without modifying the created_at. My final working UpdateInput looks like that:

{
  Key: {
    id: {
      S: "some_unique_id"
    }
  },
  TableName: "test",
  ExpressionAttributeNames: {
    #t: "created_at",
    #c: "count"
  },
  ExpressionAttributeValues: {
    :t: {
      S: "2015-09-26T15:58:57+12:00"
    },
    :c: {
      N: "1"
    }
  },
  UpdateExpression: "SET #t = if_not_exists(#t, :t) ADD #c :c"
}
Piotr Zurek
  • 2,800
  • 2
  • 24
  • 32
27

You can do this with UpdateItem API and the UpdateExpression because of your use case. Since count will be a Number type here, you can use the SET or ADD expressions:

The documentation for ADD tells you that you can use it for Number types (emphasis mine):

  • ADD - Adds the specified value to the item, if the attribute does not already exist. If the attribute does exist, then the behavior of ADD depends on the data type of the attribute:

    • If the existing attribute is a number, and if Value is also a number, then Value is mathematically added to the existing attribute. If Value is a negative number, then it is subtracted from the existing attribute.

    If you use ADD to increment or decrement a number value for an item that doesn't exist before the update, DynamoDB uses 0 as the initial value. Similarly, if you use ADD for an existing item to increment or decrement an attribute value that doesn't exist before the update, DynamoDB uses 0 as the initial value. For example, suppose that the item you want to update doesn't have an attribute named itemcount, but you decide to ADD the number 3 to this attribute anyway. DynamoDB will create the itemcount attribute, set its initial value to 0, and finally add 3 to it. The result will be a new itemcount attribute in the item, with a value of 3.

For your example, you could have your UpdateExpression be ADD #c :n, where :n has an ExpressionAttributeValue of the Number type, 1 is the value, and #c has the ExpressionAttributeName substitution for count. You need to use a placeholder for count because it is a reserved word.

See more examples on the Modifying Items and Attributes with Update Expressions

mkobit
  • 43,979
  • 12
  • 156
  • 150