PynamoDB icon indicating copy to clipboard operation
PynamoDB copied to clipboard

New feature to allow all ReturnValues valid values on update item

Open victoreufrasio opened this issue 8 years ago • 9 comments

DynamoDB UpdateItem operation receives an optional parameter named ReturnValues that allows us to get the item attributes as they appeared either before or after they were updated. Its valid values are: NONE | ALL_OLD | UPDATED_OLD | ALL_NEW | UPDATED_NEW.

PynamoDB high level API is always passing ALL_NEW.

Advantages of allowing the other options:

  • We could save a GetItem operation when we need to update an item but also need to get its old values;
  • We could save network bandwidth by sending NONE when we don't need the return values.

Thanks in advance.

victoreufrasio avatar May 09 '17 03:05 victoreufrasio

Internal Thoughts:

  • users can achieve the desired behavior through the low-level api
  • do we want to allow this behavior or does it break any assumptions on the model?
  • can we move from ALL_NEW to UPDATED_NEW safely as the default?

jpinner-lyft avatar Nov 10 '17 00:11 jpinner-lyft

Currently, we return the dictionary that changed. We can add optional fields (or have a way to make set settings in the metaclass on the model) so that we can change this behavior but leave the default as the current behavior so we don't break things.

lita avatar Nov 10 '17 19:11 lita

@lita beyond the return value we also update the item with the attributes returned, so changing the return value also affects keeping the item in-sync with the database

jpinner-lyft avatar Nov 10 '17 19:11 jpinner-lyft

Ah I see. At the very least, we can add in the option to set between ALL_NEW and UPDATED_NEW with minimal impact. Adding the other options can be a bigger release.

lita avatar Nov 10 '17 20:11 lita

If we were to set NONE there would be the question of if we should apply the update operations locally to item.

jpinner-lyft avatar Nov 10 '17 20:11 jpinner-lyft

Talked with Jeff, it seems like the best approach is to add a param in the update method to allow these behaviors. Starting off with UPDATED_NEW seems pretty reasonable.

With the current implementation, we can apply the local update operations with NONE, as we would get an exception if the update failed. But if we start adding if_not_set or list_append, we can't do that anymore as the data model could get out of sync.

lita avatar Nov 10 '17 20:11 lita

We still have a need for this feature, any chance there's a suggested path to updating an item and getting it's old value in an atomic operation?

MattShippo avatar Apr 15 '25 16:04 MattShippo

The semantics of Model.update are to update the model in-place and return None, which is why we pass ALL_NEW.

We can think up changes or amendments to the PynamoDB API to enable this, in a way that's not confusing to other users. Alternatively, you can always use boto directly, especially if what you need is something specific that doesn't map well to "ORM".

ikonst avatar Apr 16 '25 16:04 ikonst

I should have read through the entire thread originally. It turns out PynamoDB does expose this functionality, just not on the model as I initially expected and for reasons @ikonst stated.

I was able to use the low level connection object to do this.

        result = self.get_connection().update_item(
            self.Meta.table_name,
            hash_key=self.pk,
            range_key=self.sk,
            actions=[User.last_charge_received_time.set(datetime.now(timezone.utc))],
            return_values=ALL_OLD,
        )
        return datetime.fromisoformat(result["Attributes"]["last_charge_received_time"]["S"])

MattShippo avatar Apr 16 '25 19:04 MattShippo