avatar

Andres Jaimes

Inserting and updating items to DynamoDB lists and maps

By Andres Jaimes

- 3 minutes read - 473 words

Should I use a map or a list? A simple rule:

  • If you need to update or remove an item, lists only allow you to do it by index. While maps let you do it by key.

Their simplified representation goes like this:

1{
2  "someMap": {
3    "key1": "value1",
4    "key2": "value2",
5  },
6  "someList": ["value1", "value2"]
7}

Inserting and updating to a map

The following example adds or updates an instance of “SomeItem” as a json string into a map field called someMapField. A sample simplified record looks like this:

1{
2  "id": "someKey",
3  "someMapField": {
4    "itemKey": "itemValue as json string"
5  }
6}

The code to add or update the record includes a SET command followed by a path, in this case the-field-name.the-item's-key. If the value does not exist, it will be added; otherwise it will be updated.

 1def update(someKey: String, item: SomeItem): Future[SomeItem] = {
 2  val updateExpression: String =
 3    s"SET someMapField.#itemKey = :itemValue"
 4
 5  val names: Map[String, String] = Map(
 6    "#itemKey" -> item.key
 7  val values: Map[String, AttributeValue] = Map(
 8    ":itemValue" -> new AttributeValue().withS(Json.toJson(item).toString))
 9  val request = new UpdateItemRequest()
10    .withTableName("tableName")
11    .withKey(Map("id" -> new AttributeValue().withS(someKey)))
12    .withUpdateExpression(updateExpression)
13    .withExpressionAttributeNames(names)
14    .withExpressionAttributeValues(values)
15    .withReturnValues(ReturnValue.ALL_NEW)
16
17  Future {
18    val result = dynamodb.getClient.updateItem(request).getAttributes.toMap
19    fromAttributeMap(result)
20  }
21}

A condition can be added to insert an item only when it does not exist:

1UpdateExpression = "SET map.#number = :string"
2ExpressionAttributeNames = { "#number" : "1" }
3ExpressionAttributeValues = { ":string" : "the string to store in the map at key value 1" }
4ConditionExpression = "attribute_not_exists(map.#number)"

Inserting and updating to a list

We can insert an item to a list by using the ADD command.

 1val updateExpression: String =
 2  s"ADD fieldName :fieldValue"
 3
 4val values: Map[String, AttributeValue] = Map(
 5  ":fieldValue" -> new AttributeValue().withSS("value")
 6val request = new UpdateItemRequest()
 7  .withTableName("tableName")
 8  .withKey(Map("id" -> new AttributeValue().withS("someId")))
 9  .withUpdateExpression(updateExpression)
10  .withExpressionAttributeValues(values)
11  .withReturnValues(ReturnValue.ALL_NEW)
12
13Future {
14  val result = dynamodb.getClient.updateItem(request).getAttributes.toMap
15  fromAttributeMap(result)
16}

As we mentioned previously, when we want to update an item from a list we have to know its index beforehand. This example gets the index of an item and then uses SET to modify its value.

 1const userIdx = users.map(user => user.M.id.S).indexOf(userId)
 2
 3const deactivateUserParams = {
 4    TableName: USERS_CATEGORY_TABLE_DEV,
 5    Key: {id: {S: catId}},
 6    UpdateExpression: `SET updatedAt = :updated_at, #users[${userIdx}].#status = :new_status`,
 7    ExpressionAttributeNames: {
 8        "#users": 'users',
 9        "#status": "status"
10    },
11    ExpressionAttributeValues: {
12        ":new_status": {"S": "INACTIVE"},
13        ":updated_at": {"S": new Date().toISOString()}
14    },
15    ReturnValues: "UPDATED_NEW",
16}

References