Attribute in DynamoDB cannot be updated by lambda function

0

Hello,

I was following the serverless workshop examples, but running into a problem! My lambda handlerhere can't update the attribute 'status' shown in the schema.

The error message is a ValidationException complaining about the document path log here.

How should I troubleshoot this further? Has someone had this problem before?

Thanks a lot!

Here's the lambda handler code:

import json
import os
import boto3

from decimal import Decimal


ORDERS_TABLE = os.environ['ORDERS_TABLE_NAME']
dynamodb = boto3.resource('dynamodb')
ddbTable = dynamodb.Table(ORDERS_TABLE)

def lambda_handler(event, context):
    response = None
    print(str(event))
    try:

        status_code = 200
        
        order_data = event['detail']['data']
        
        status = order_data['status']
        orderId = order_data['orderId']
        userId = order_data['userId']

        key={ 
        "userId": userId,
        "orderId": orderId}

        update_expression = "SET #data.#status = :status"
        expression_attribute_values = {":status": status} 
        expression_attribute_names = {"#data": "data", "#status": "status"}
        print(str(update_expression))
        response = ddbTable.update_item(
           Key=key,
           UpdateExpression=update_expression,
           ExpressionAttributeValues=expression_attribute_values,
           ExpressionAttributeNames=expression_attribute_names
        )
    except Exception as err:
        status_code = 400
        response_body = {"Error:": str(err)}
        print(str(err))

    return {
        "statusCode": status_code,
        "body" :  response
    
    }
Felix
asked 2 months ago761 views
2 Answers
1
Accepted Answer

This is most likely due to the fact that data dict does not exist in the current item you're trying to update. You cannot update status if it's within a dict that does not exist, you can catch the exception and add the entire dict which should provide a workaround.

status = order_data['status']
orderId = order_data['orderId']
userId = order_data['userId']

key={ 
    "userId": userId,
    "orderId": orderId
}

update_expression = "SET #data.#status = :status"
expression_attribute_values = {":status": status} 
expression_attribute_names = {"#data": "data", "#status": "status"}
try:
    response = ddbTable.update_item(
        Key=key,
        UpdateExpression=update_expression,
        ExpressionAttributeValues=expression_attribute_values,
        ExpressionAttributeNames=expression_attribute_names
    )
except ClientError as e:
    if e.response['Error']['Code'] == 'ValidationException':
        expression_attribute_values = {":data": {"data":{
            "status":status
        }}} 
        expression_attribute_names = {"#data": "data"}
        update_expression = "SET #data = :data"
        response = ddbTable.update_item(
            Key=key,
            UpdateExpression=update_expression,
            ExpressionAttributeValues=expression_attribute_values,
            ExpressionAttributeNames=expression_attribute_names
        )
profile pictureAWS
EXPERT
answered 2 months ago
  • That's not the case though. I've checked that both 'data' dict and the data['status'] attribute are present. Yet it's still complaining.

    I tried your suggestion, and it results in something stranger. DynamoDB created a separate item in that table, with the same Hashkey (userId) and default value for rangeKey ( orderId is 1), and the new item simply containing the actual data payload specified in the command.

    Just curious.. Maybe it's simply a edge case with the attribute names being reserved words?

  • The behaviour is not strange, it confirms your issue is that you think the key contains different values than what it actually should. Hard-code the keys of the items you expect to target.

  • You are right! Apparently a wrong range key was used during my testing, so it was trying to update a non-existing item. Much appreciate for the help!

-1

Ensure that your update expression is correctly formatted

import boto3

dynamodb = boto3.resource('dynamodb') table = dynamodb.Table('YourTableName')

def lambda_handler(event, context): response = table.update_item( Key={ 'PrimaryKey': event['PrimaryKey'] }, UpdateExpression="SET attribute1 = :val1, attribute2 = :val2", ExpressionAttributeValues={ ':val1': event['value1'], ':val2': event['value2'] } ) return response

answered 2 months ago
  • Thanks for replying. From the error, seems the problem is with the SET expression. Due to the table schema naming in the example, the path to the nested attribute should be "data.status". Since both "data" and "status" are special words, they has to be substitute with the # prefix. So I'm lost about why this won't pass the validation.. P.s. I've pasted the actual handler code in the updated question.

You are not logged in. Log in to post an answer.

A good answer clearly answers the question and provides constructive feedback and encourages professional growth in the question asker.

Guidelines for Answering Questions