Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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?

like image 554
Myroslav Hryshyn Avatar asked Oct 27 '17 16:10

Myroslav Hryshyn


People also ask

How to update items in DynamoDB?

To update an existing item in an Amazon DynamoDB table, you use the UpdateItem operation. You must provide the key of the item that you want to update. You must also provide an update expression, indicating the attributes that you want to modify and the values that you want to assign to them.

Does DynamoDB Update create if not exists?

Edits an existing item's attributes, or adds a new item to the table if it does not already exist.

Does Put item update item DynamoDB?

The main difference between the two is, PutItem will Replace an entire item while UpdateItem will Update it.

Are DynamoDB updates Atomic?

DynamoDB provides four operations for basic create, read, update, and delete (CRUD) functionality. All these operations are atomic.


1 Answers

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
like image 195
Chris Shenton Avatar answered Oct 09 '22 06:10

Chris Shenton