Reputation: 1152
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
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
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