Search code examples
amazon-dynamodbdynamodb-queries

Using list_append with list of maps in DynamoDB


I have a DynamoDB table with a schema similar to the below. I want to essentially run an "upsert" function on the jobs attribute that will either add the jobs attribute or append to the list.

When executing my code, I am getting an error message:

An error occurred (ValidationException) when calling the UpdateItem operation: Invalid UpdateExpression: Incorrect operand type for operator or function; operator or function: list_append, operand type: M

Schema:

{
  "jobs": [
    {
      "event_id": "event_id",
      "job_map": [
        {
          "key1": "val1",
          "key2": "val2"
        }
      ],
      "job_start": "time_stamp"
    }
  ],
  "p_key": "some_id"
}

Example/documentation:

  1. Running upsert functions on Dynamo
  2. Appending to Dynamo lists
  3. SO question with answers I am pretty sure I'm following

Sample code:

p_key_string = 'some_id'
event_id = '123'
job_start = 'timestamp_string'

task_map = []
for item in items:
    task_map.append({
        "M": {
            'key1': {"S": item.get('val1')},
            'key2': {"S": item.get('val2')}
        }
    })

args = {
    'Key': {
        'p_key': p_key_string
    },
    'UpdateExpression': "SET p_key = :p_key, #ri = list_append(#ri, :vals)",
    'ConditionExpression': "attribute_not_exists(p_key) OR p_key = :p_key",
    'ExpressionAttributeNames': {
        "#ri": "jobs"
    },
    'ExpressionAttributeValues': {
        ':p_key': p_key_string,
        ':vals': {
            "L": [{
                "M": {
                    "event_id": { "S": event_id},
                    "job_start": { "S": job_start},
                    'job_map': { "L": task_map}
                }
            }]
        }
    }
}

dynamo_client.update_item(**args)

Based on the error I tried a simpler query, but actually got the same error.

...
':vals': {
    "L": [
        { "S": event_id},
        { "S": job_start}
    ]
}
...

So really not sure what I am missing.


Solution

  • I'm not entirely sure I understand why, but by removing the data type declarations, I was able to move past the error. The code above had some additional errors, but the below changes appear to be working for me.

    ...
    task_map.append({
      'key1': 'val1',
      'key2': 'val2'
    })
    ...
    
    ...
    args = {
      'Key': {
        'p_key': p_key_string
      },
      'UpdateExpression': "SET jobs = list_append(if_not_exists(jobs, :empty_list), :vals)",
      'ExpressionAttributeValues': {
        ':vals': [{
          "event_id": event_id,
          "job_start": job_start,
          "job_map": task_map
        }],
        ":empty_list": []
      }
    }
    ...