Putting/Updating item in DynamoDB fails for the UpdateExpression syntax

16,006

Have you tried this? http://docs.aws.amazon.com/amazondynamodb/latest/developerguide/ExpressionPlaceholders.html#ExpressionAttributeNames

set_query = "SET #service_name.current_sha = :current, #service_name.prev_sha = :prev, #service_name.deployed = :is_deployed, #service_name.current_status = :current_status"
updated = self.dynamodb.update_item(
    Key = {
        'environment': environment
    },
    UpdateExpression = set_query,
    ExpressionAttributeValues = {
        ':current': service_data.get('current'),
        ':prev': service_data.get('prev'),
        ':current_status': service_data.get('status'),
        ':is_deployed': service_data.get('deployed')
    },
    ExpressionAttributeNames = {
         '#service_name': service_name,
    },
    ReturnValues = "ALL_NEW"
)
Share:
16,006
hjpotter92
Author by

hjpotter92

teh twitters be horrific!!! #SOreadytohelp

Updated on June 12, 2022

Comments

  • hjpotter92
    hjpotter92 almost 2 years

    I've created a DynamoDB table, and in my Python code, I have the resource initialised as follows:

    self.dynamodb = self.session.resource('dynamodb').Table('aws-ci')
    

    The table has just one index/key, with the name environment. I am trying to PUT into it, an object as follows:

    {
      "environment": "beta",
      "X": {
        "current_sha": "sha1",
        "deployed": true,
        "prev_sha": "sha2",
        "status": "inactive"
      },
      "Y-Z": {
        "current_sha": "sha1",
        "deployed": false,
        "prev_sha": "sha2",
        "status": "active"
      }
    }
    

    where, X and Y-Z are the names of micro-services. My insertion code is as follows:

    def put_service_data(self, environment, service_name, service_data, status = None):
        get_previous = self.dynamodb.get_item(
            Key = {
                'environment': environment
            }
        ).get(service_name)
        service_data['prev'] = get_previous and get_previous.get('current_sha') or 'NULL'
        if status == 'rollback' and get_previous:
            service_data['current'] = get_previous.get('current_sha')
            service_data['prev'] = get_previous.get('prev_sha')
        set_query = "SET {0}.current_sha = :current, {0}.prev_sha = :prev, {0}.deployed = :is_deployed, {0}.current_status = :status".format(service_name)
        updated = self.dynamodb.update_item(
            Key = {
                'environment': environment
            },
            UpdateExpression = set_query,
            ExpressionAttributeValues = {
                ':current': service_data.get('current'),
                ':prev': service_data.get('prev'),
                ':status': service_data.get('status'),
                ':is_deployed': service_data.get('deployed')
            },
            ReturnValues = "ALL_NEW"
        )
        return updated
    

    Previously, instead of {0}.current_status, I had {0}.status, but that raised the following error:

    An error occurred (ValidationException) when calling the UpdateItem operation: Invalid UpdateExpression: Attribute name is a reserved keyword; reserved keyword: status

    Anyway, I changed that attribute name name to current_status and tried the insertion again, only this time I am receiving:

    An error occurred (ValidationException) when calling the UpdateItem operation: The document path provided in the update expression is invalid for update

    when trying to set attributes for service X, and the following when trying for Y-Z:

    An error occurred (ValidationException) when calling the UpdateItem operation: Invalid UpdateExpression: Syntax error; token: "-", near: "Y-Z"

    I'm currently unable to understand how the update_item call should work.