when updating dynamodb table i get this error:
ERROR:root:------- here: An error occurred (ValidationException) when calling the
UpdateItem operation: The provided expression refers to an attribute that does not exist
in the item
I think its the expression in update_vote function that causes trouble
#!/usr/bin/env python3
import boto3
import json
import logging
import sys
logging.basicConfig(stream=sys.stdout, level=logging.INFO)
queue = boto3.resource('sqs', region_name='us-east-1').get_queue_by_name(QueueName="erjan")
table = boto3.resource('dynamodb', region_name='us-east-1').Table('Votes')
def process_message(message):
try:
payload = message.message_attributes
voter = payload['voter']['StringValue']
vote = payload['vote']['StringValue']
logging.info("Voter: %s, Vote: %s", voter, vote)
store_vote(voter, vote)
update_count(vote)
message.delete()
except Exception as e:
print('-------')
print('message.attr')
print(message.message_attributes)
try:
vote = payload['vote']['StringValue']
logging.error("Failed to process message")
logging.error('vote %d' % vote)
except TypeError:
logging.error("yes error catched")
def store_vote(voter, vote):
try:
logging.info('table put item.......')
print('table put item......')
response = table.put_item(
Item={'voter': voter, 'vote': vote}
)
except:
logging.error(" Failed to store message")
raise
#this function causes error i think
def update_count(vote):
logging.info('update count....')
print('update count....')
table.update_item(
Key={'voter': 'default_voter'},
UpdateExpression="set #vote = #vote :incr", #this update expression
ExpressionAttributeNames={'#vote': vote},
ExpressionAttributeValues={':incr': 1}
)
if __name__ == "__main__":
while True:
try:
messages = queue.receive_messages(MessageAttributeNames=['vote','voter'])
except KeyboardInterrupt:
logging.info("Stopping...")
break
except:
logging.error(sys.exc_info()[0])
continue
for message in messages:
process_message(message)
dynamodb table has 1 partition key - 'voter'. it should store counts for how many clicks "a" or "b" received.
CodePudding user response:
You may want to set a default value if currently there is no value stored to be incremented:
def update_count(vote):
logging.info('update count....')
print('update count....')
table.update_item(
Key={'voter': 'default_voter'},
UpdateExpression="set #vote = if_not_exists(#vote, :start) :incr",
ExpressionAttributeNames={'#vote': vote},
ExpressionAttributeValues={':incr': 1, ':start': 0}
)
Notice the if_not_exists
which will set the initial value for the votes to 0.
CodePudding user response:
The reason you are seeing this exception is due to the fact no vote
attribute exists in your item currently, causing the exception:
The provided expression refers to an attribute that does not exist in the item
1. Use ADD
instead of SET
This is the recommended approach. It automatically sets the value to 0 should it not exist, then adds your provided value. The only time you would use option #2 is when the attribute is stored within a nested value, for which ADD
will not work.
Use the ADD action in an update expression to add a new attribute and its values to an item. DOCS
ADD path value
table.update_item(
Key={'voter': 'default_voter'},
UpdateExpression="ADD #vote :incr",
ExpressionAttributeNames={'#vote': vote},
ExpressionAttributeValues={':incr': 1}
)
2. Use if_not_exists
Function
If the item does not contain an attribute at the specified path, if_not_exists evaluates to value; otherwise, it evaluates to path.
This approach requires you to set a value which is initially set if the attribute should not exist: :empty=0
. This is more of a workaround than how you are recommended to add values in DynamoDB.
if_not_exists (path, value)
table.update_item(
Key={'voter': 'default_voter'},
UpdateExpression="set #vote = if_not_exists(#vote, :empty) :incr",
ExpressionAttributeNames={'#vote': vote},
ExpressionAttributeValues={':incr': 1, ':empty': 0}
)