David Christie
David Christie

Reputation: 141

DynamoDB: list_append alternative for sets

I am trying to do an update operation on a dynamodb string set attribute. For lists, the operation would be

set #key = list_append(if_not_exists(#key, :empty_list), :newValue)

But this produces a list attribute. Is there an alternative for list_append but for sets?

Upvotes: 1

Views: 494

Answers (1)

Maurice
Maurice

Reputation: 13197

Since DynamoDB can't store empty sets this is actually fairly easy, you can just use the ADD operator.

Here's an example I've built in Python:

import boto3

TABLE_NAME = "set-demo"


def create_table():
    ddb = boto3.client("dynamodb")
    ddb.create_table(
        AttributeDefinitions=[
            {"AttributeName": "PK", "AttributeType": "S"},
            {"AttributeName": "SK", "AttributeType": "S"}
        ],
        TableName=TABLE_NAME,
        KeySchema=[
            {"AttributeName": "PK", "KeyType": "HASH"},
            {"AttributeName": "SK", "KeyType": "RANGE"}
        ],
        BillingMode="PAY_PER_REQUEST"
    )

def add_to_set(item_id: str, value: str):
    table = boto3.resource("dynamodb").Table(TABLE_NAME)

    table.update_item(
        Key={
            "PK": f"ITEM#{item_id}",
            "SK": f"METADATA",
        },
        UpdateExpression="ADD #set_name :set_value",
        ExpressionAttributeNames={
            "#set_name": "values"
        },
        ExpressionAttributeValues={
            ":set_value": {value},  # needs to be a set type
        }
    )

if __name__ == "__main__":
    # create_table()
    add_to_set("a", "value_1")
    add_to_set("a", "value_2")
    add_to_set("a", "value_1")

In python it's sufficient to pass a value with the datatype set in the ExpressionAttributeValues for boto3 to know it needs to convert it into a set under the hood.

When I call add_to_set for the first time, it will create the set attribute and subsequent calls are just updates to the attribute.

This is what the item looks like in the end:

{
  "PK": {
    "S": "ITEM#a"
  },
  "SK": {
    "S": "METADATA"
  },
  "values": {
    "SS": [
      "value_1",
      "value_2"
    ]
  }
}

Upvotes: 3

Related Questions