Search code examples
pythonamazon-web-servicesamazon-dynamodbdynamodb-queries

Update attributes of DynamoDB table item


While defining my DynamoDB table, I selected filename as the unique attribute or primary key. In this function, I want to modify some columns of the entry with a particular filename. I tried this after following another SO answer:

def update_item_in_db(filename, archive_path):
    table = dynamodb.Table(dynamodb_table_name)
    try:
        logger.info(f'Updating dynamo table for filename: {filename}')
        response = table.update_item(
            Key={'filename': filename},
            AttributeUpdates={
                'archive_path': archive_path,
                'archived_on': datetime.today().strftime('%Y-%m-%d-%H:%M:%S')
            },
        )
    except Exception as e:
        raise Exception(f"Unable to insert filename into dynamodb: {e}") 
    return response

but I get an error that:

Parameter validation failed:\nInvalid type for parameter AttributeUpdates.archive_path, value: archive/100-ff0-uat/1591282803734/issues_1591282803734.zip, type: <class 'str'>, valid types: <class 'dict'>\nInvalid type for parameter AttributeUpdates.archived_on, value: 2021-11-21-15:06:46, type: <class 'str'>, valid types: <class 'dict'>",

Then I also tried:

        response = table.update_item(
            {
                'filename': filename,
                'archive_path': archive_path,
                'archived_on': datetime.today().strftime('%Y-%m-%d-%H:%M:%S')
            }
        )

but then I get the following error:

 "Unable to insert filename into dynamodb: update_item() only accepts keyword arguments.",

What's the correct syntax to update an item?

Note that I only want to UPDATE/MODIFY and not delete and re-insert.


Solution

  • The first approach uses a deprecated syntax. The second one is closer to what you want to do.

    Something like this should work:

    from datetime import datetime
    
    import boto3
    
    dynamodb = boto3.resource("dynamodb")
    
    def update_item_in_db(filename, archive_path):
        table = dynamodb.Table(dynamodb_table_name)
    
        table.update_item(
            Key={
                "filename": filename
            },
            UpdateExpression="SET #archive_path = :archive_path, #archived_on = :archived_on",
            ExpressionAttributeNames={
                "#archive_path": "archive_path",
                "#archived_on": "archived_on"
            },
            ExpressionAttributeValues={
                ":archive_path": archive_path,
                ":archived_on": datetime.today().strftime('%Y-%m-%d-%H:%M:%S')
            }
        )
    

    The ExpressionAttributeNames and ExpressionAttributeValues allow you to use reserved keywords in the UpdateExpression, that's why they're commonly used.

    (I didn't run the code, there may be typos.)