turtle_in_mind
turtle_in_mind

Reputation: 1152

boto3 conditionally delete in python

I have a dynamoDB DataBase with the following schema:

user    id    payload
123     abcd   some value
456     abcd   some value     

How do i delete the id abcd corresponding to user 456? what if user 456 didn't exist? I tried:

try:
    resource.delete_item(
    Key={'user': 456,
        'id': 'abcd'
        })
except botocore.exceptions.ClientError as e:
        if e.response['Error']['Code'] == 'ConditionalCheckFailedException':
            print(e.response['Error']['Message'])
        else:
            raise
    else:
        print("DeletePortfolio Successful...")

I always end up getting the statement "DeletePortfolio Successful" even if i put a random user like 478, or keep the user 456 and put an incorrect id like 'defg'. How do i do a conditional delete only if key and value is present? Thanks

Upvotes: 1

Views: 2662

Answers (2)

shearn89
shearn89

Reputation: 887

I know this is old, but I found this via Google and will probably need it in future.

Given a DDB table with a partition key of id, and an extra attribute Test, we can delete a row only if the value of Test == foo like so:

import json
import boto3
import botocore

dynamo_db = boto3.client('dynamodb')

def lambda_handler(event, context):
    try:
        response = dynamo_db.delete_item(
            TableName='TestTable',
            Key={'id': {'S': 'myID'}},
            ExpressionAttributeNames={
                '#sk': 'Test'
            },
            ExpressionAttributeValues={
                ':sk': {'S': 'bar'},
            },
            ConditionExpression='#sk = :sk'
        )
        return response
    except botocore.exceptions.ClientError as e:
        if e.response['Error']['Code'] == 'ConditionalCheckFailedException':
            print("conditional delete failed because attribute did not match")
        else:
            raise e
    print('done')

For simple field names and values, the ExpressionAttributeNames and ExpressionAttributeValues parameters are possibly redundant, but more rigorous in case of special characters in the field.

The reason this conditional delete is useful is that DynamoDB is eventually consistent (by default). Let's say you're tracking sessions - a process might run to delete a session on a disconnection, but the user may reconnect in the meantime. If you're partition key is the user ID in that case, you don't want to delete the new session if the row has been updated in between triggering and deleting. So a conditional delete lets you verify that you're deleting the old row by checking a specific attribute (say, a timestamp or something).

Upvotes: 0

turtle_in_mind
turtle_in_mind

Reputation: 1152

I figured it out.

Hope this helps anybody out there

def deleteItem(user, id):
    try:
        resource.delete_item(
           Key={'user': user, 'id': id},
           ConditionExpression='attribute_exists(id)'
           )
    except botocore.exceptions.ClientError as e:
        if e.response['Error']['Code'] in ['ConditionalCheckFailedException',
         'ParamVAlidationError']:
              print(e.response['Error']['Message'])
        else:
            raise
    else:
        print("delete successful")

Upvotes: 2

Related Questions