Moto: dynamodb item update doesn't support UpdateExpression (SET)

Created on 7 Sep 2016  路  9Comments  路  Source: spulec/moto

Documentation on UpdateExpression (SET):

http://docs.aws.amazon.com/amazondynamodb/latest/developerguide/Expressions.Modifying.html#Expressions.Modifying.UpdateExpressions.SET

Exception:

self = Item: {'Attributes': {'Hk': {'S': 'queue_name:0'}, 'Rk': {'S': '4I7CaHMQPNhhGkv_AyOCyP61QYZJETkyEccZletk'}}}
update_expression = 'SET MT = if_not_exists(MT, :message_type), MC = if_not_exists(MC, :message_content), SI = if_not_exists(SI, :sender_i...first_visible_time), RT = if_not_exists(RT, :minus_1), RC = if_not_exists(RC, :zero), DT = if_not_exists(DT, :minus_1)'
expression_attribute_names = {}
expression_attribute_values = {':first_visible_time': {'N': '63608879137.886993408203125'}, ':message_content': {'S': '$'}, ':message_type': {'S': '$type_0'}, ':minus_1': {'N': '-1'}, ...}

    def update(self, update_expression, expression_attribute_names, expression_attribute_values):
        ACTION_VALUES = ['SET', 'set', 'REMOVE', 'remove']

        action = None
        for value in update_expression.split():
            if value in ACTION_VALUES:
                # An action
                action = value
                continue
            else:
                # A Real value
                value = value.lstrip(":").rstrip(",")
            for k, v in expression_attribute_names.items():
                value = value.replace(k, v)
            if action == "REMOVE" or action == 'remove':
                self.attrs.pop(value, None)
            elif action == 'SET' or action == 'set':
>               key, value = value.split("=")
E               ValueError: need more than 1 value to unpack

Specifically, it's having trouble parsing this:

SET MT = if_not_exists(MT, :message_type), MC = if_not_exists(MC, :message_content), SI = if_not_exists(SI, :sender_id), ST = if_not_exists(ST, :now), FV = if_not_exists(FV, :first_visible_time), NV = if_not_exists(NV, :first_visible_time), RT = if_not_exists(RT, :minus_1), RC = if_not_exists(RC, :zero), DT = if_not_exists(DT, :minus_1)

Hk is the hash key and Rk is the range key.

Sorry I haven't written a simple test case that reproduces the error. I'm at work and I need to move on to other things.

I produced this error on commit ea319698aab8c8e1c6f55d4e115808c725bac268 of moto.

Most helpful comment

trying to use list_append

 table.update_item(
    Key={
        'request_id': unique_id
    },
    ExpressionAttributeValues={':file_name': ['ABC']},
    UpdateExpression='SET file_names = list_append(file_names, :file_name)'
)

but when I query dynamo later the value of file_names is list_append(file_names, :file_name)
same issue when i'm trying to increment value, the value after I query is the update expression

All 9 comments

Seeing the same issue. Looks like if_not_exists and list_append operations are not supported yet. Furthermore, after splitting on the = sign there's a possibility for both the key and value to have spurious whitespace. I'd recommend trimming them.

Unsubscribing because we ended up switching to dynalite for this test.

Anyone looking into this?

I use the latest moto v0.4.30 dynamodb2, and it is breaking on two different Python versions.

With Python 2.7.10, I get an error similar to this, which is a ValueError: too many values to unpack.

self = <botocore.retryhandler.ExceptionRaiser object at 0x108bb0550>, attempt_number = 1, caught_exception = ValueError('too many values to unpack',)

    def _check_caught_exception(self, attempt_number, caught_exception):
        # This is implementation specific, but this class is useful by
        # coordinating with the MaxAttemptsDecorator.
        # The MaxAttemptsDecorator has a list of exceptions it should catch
        # and retry, but something needs to come along and actually raise the
        # caught_exception.  That's what this class is being used for.  If
        # the MaxAttemptsDecorator is not interested in retrying the exception
        # then this exception just propogates out past the retry code.
>       raise caught_exception
E       ValueError: too many values to unpack

With Python 3.5.2, I get an error similar to this, which is a ValueError: too many values to unpack (expected 2).

self = Item: {'Attributes': {'user_id': {'S': '[email protected]'}}}
update_expression = 'SET payload.allergic_to_dairy=:e0,payload.allergic_to_bellpepper=:e1,payload.allergic_to_cilantro=:e2,payload.allergi...same=:e14,payload.allergic_to_garlic=:e15,payload.allergic_to_cheese=:e16,payload.allergic_to_soy=:e17,updated_at=:e18'
expression_attribute_names = {}, expression_attribute_values = {':e0': {'BOOL': True}, ':e1': {'BOOL': True}, ':e10': {'BOOL': True}, ':e11': {'BOOL': True}, ...}

    def update(self, update_expression, expression_attribute_names, expression_attribute_values):
        ACTION_VALUES = ['SET', 'set', 'REMOVE', 'remove']

        action = None
        for value in update_expression.split():
            if value in ACTION_VALUES:
                # An action
                action = value
                continue
            else:
                # A Real value
                value = value.lstrip(":").rstrip(",")
            for k, v in expression_attribute_names.items():
                value = value.replace(k, v)
            if action == "REMOVE" or action == 'remove':
                self.attrs.pop(value, None)
            elif action == 'SET' or action == 'set':
>               key, value = value.split("=")
E               ValueError: too many values to unpack (expected 2)

venv/lib/python3.5/site-packages/moto/dynamodb2/models.py:129: ValueError

This is not a problem working with an actual DynamoDB on AWS.

If you need extensive dynamodb support, it may be worth looking into dynalite or an alternative. I don't use dynamodb much so this isn't high on my priority list and it doesn't seem like we have anyone else to step up.

Is this still an issue? Swear I used it the other day.

Closing because the DynamoDB support has received much love lately and this is likely fixed. Please reopen if found to be otherwise.

trying to use list_append

 table.update_item(
    Key={
        'request_id': unique_id
    },
    ExpressionAttributeValues={':file_name': ['ABC']},
    UpdateExpression='SET file_names = list_append(file_names, :file_name)'
)

but when I query dynamo later the value of file_names is list_append(file_names, :file_name)
same issue when i'm trying to increment value, the value after I query is the update expression

any update?

I'm also wondering about this

Was this page helpful?
0 / 5 - 0 ratings