DynamoDb update using boto3

Question:

I am writing a lambda function to update dynamodb item. But the problem is that when I give

 {
  "employee_id": "1",
  "last_name": "jane",
  "first_name": "anderson"
}

It works fine but if you remove the last_name or the first_name the program crashes.I want to make it dynamic like if I provice last_name and employee_id it changes last_name only and same goes with first_name. If I provide both first_name and last_name it changes both.
Note: employee_id is used here to fetch the data

 {
  "employee_id": "1",
  "last_name": "jane"
}

It gives an error saying that:

{
  "errorMessage": "'first_name'",
  "errorType": "KeyError",
  "stackTrace": [
    "  File "/var/task/lambda_function.py", line 10, in lambda_handlern    first_name= event['first_name']n"
  ]
}

Lambda function:

import boto3
import json

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

def lambda_handler(event, context):
    employee_id = event['employee_id']
    last_name= event['last_name']
    first_name= event['first_name']
    update = table.update_item(
        Key={
            'employee_id': employee_id
        },
        ConditionExpression= 'attribute_exists(employee_id)',
        UpdateExpression='SET first_name = :val1, last_name = :val2',
        ExpressionAttributeValues={
            ':val1': last_name,
            ':val2': first_name
        }
    )
Asked By: user13879829

||

Answers:

There are few possibilities you could deal with the issue. If the first_name is absent you could either skip the filed in DynamoDB, or provide some default/empty value. This is use-case specific and depends on how you want to deal with the missing first_name. You could also throw an error if such situation should not be allowed.

Either way, there is a check performed if first_name exists in the event.

Below, is an example of the first option:

import boto3
import json

dynamodb = boto3.resource('dynamodb')
table = dynamodb.Table('Employee-wahaj')

def lambda_handler(event, context):

    employee_id = event['employee_id']
    last_name = event['last_name']

    UpdateExpression = 'SET last_name = :val1'
    ExpressionAttributeValues = {':val1': last_name }


    if 'first_name' in event:
        
        first_name= event['first_name']
        UpdateExpression = 'SET last_name = :val1, first_name = :val2'
        ExpressionAttributeValues = {
                ':val1': last_name,
                ':val2': first_name
            }

    update = table.update_item(
        Key={
            'employee_id': employee_id
        },
        ConditionExpression= 'attribute_exists(employee_id)',
        UpdateExpression=UpdateExpression,
        ExpressionAttributeValues=ExpressionAttributeValues
    )

update for first and last names

Its a basic solution (just few if-else-if), as I don’t want to over complicate the example.

import boto3
import json

dynamodb = boto3.resource('dynamodb')
table = dynamodb.Table('Employee-wahaj')

def lambda_handler(event, context):

    employee_id = event['employee_id']

    if 'first_name' in event and 'last_name' not in event:

        first_name = event['first_name']
        UpdateExpression = 'SET first_name = :val1'
        ExpressionAttributeValues = {':val1': first_name }

    elif 'last_name' in event and 'first_name' not in event:

        last_name = event['last_name']
        UpdateExpression = 'SET last_name = :val1'
        ExpressionAttributeValues = {':val1': last_name}

    elif 'first_name' in event and 'last_name' in event:

        last_name = event['last_name']
        first_name= event['first_name']
        UpdateExpression = 'SET last_name = :val1, first_name = :val2'
        ExpressionAttributeValues = {
                ':val1': last_name,
                ':val2': first_name
            }

    else:
        raise ValueError("first_name and last_name not given")


    update = table.update_item(
        Key={
            'employee_id': employee_id
        },
        ConditionExpression= 'attribute_exists(employee_id)',
        UpdateExpression=UpdateExpression,
        ExpressionAttributeValues=ExpressionAttributeValues
    )
Answered By: Marcin

I wrote this quick generic routine that allows you to parse the JSON and extract the values and append it in a dictionary form for the update. The key field is located in the data argument.

def updateItem(data):
  keyField = data['keyField']

  updateExp = "SET "
  expAttribVal = {}
  count = 1

  for key, value in data.items():
    if key != "keyField": 
        if count != 1:
            updateExp = updateExp+", "
        updateExp = updateExp + key + " = :val"+str(count)
        temp = {':val'+str(count) : value}
        expAttribVal.update(temp)
        count=count+1

  try:
    response = table.update_item(
        Key={
            'keyField': keyField
        },
        UpdateExpression=updateExp,
        ExpressionAttributeValues=expAttribVal,
        ReturnValues="UPDATED_NEW"
    )
    return response
  except:
    raise        
Answered By: QuadraticEquation