Myroslav Hryshyn
Myroslav Hryshyn

Reputation: 726

Update or create nested element in dynamoDB

I want to update or create DynamoDB item to get next element:

{
    "id": 156, 
    "date": 12323233.000,
    "countries": {
        "ua": 1,
        "ru": 2}
}

I use python and boto3. So I can check if field countries exist and if not add it. But that will mean 2 DB requests.

table.update_item(
    Key={
        'id': 156,
        'date': date,
    },
    UpdateExpression='SET countries = if_not_exists(countries, :countries)',
    ExpressionAttributeValues={
        ':countries': {},
    },
)

table.update_item(
    Key={
        'id': 156,
        'date': date,
    },
    UpdateExpression='ADD countries.#country :inc',
    ExpressionAttributeNames={"#country": country},  
    ExpressionAttributeValues={
        ':inc': 1
    },
)

Is there any way to merge this 2 requests in one?

Upvotes: 6

Views: 1262

Answers (1)

Chris Shenton
Chris Shenton

Reputation: 145

I had to do something like this recently, and took a while to figure out. I've got a count I want to increment if a page doesn't already exist in my set of "done" pages. If not, it increments and adds the page number to the set. Took a while to realize you can 'append' to a list, but have to 'add' to a set.

try:
    res = dbt.update_item(
        Key={'pk': 'doc3', 'sk': 'na'},
        ReturnConsumedCapacity='INDEXES', ReturnValues='ALL_NEW',
        ExpressionAttributeNames={
            '#count': 'count',
            '#done': 'done',
        },
        ExpressionAttributeValues={
            ':1': 1,
            ':page': page,
            ':pagelist': set([page]),
        },
        ConditionExpression="(NOT contains(done, :page))",
        UpdateExpression="ADD #done :pagelist, #count :1",
    )
    print(f'rand int page={page} count={res["Attributes"]["count"]}'
          f' CU={res["ConsumedCapacity"]["Table"]}')
except ClientError as err:
    if err.response['Error']['Code'] == 'ConditionalCheckFailedException':
        print('Already got page=%s (%s)' % (page, err))
    else:
        raise

Upvotes: 1

Related Questions