Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Update nested map dynamodb

Tags:

I have a dynamodb table with an attribute containing a nested map and I would like to update a specific inventory item that is filtered via a filter expression that results in a single item from this map.

How to write an update expression to update the location to "in place three" of the item with name=opel,tags include "x1" (and possibly also f3)? This should just update the first list elements location attribute.

  {     "inventory": [     {       "location": "in place one",      # I want to update this       "name": "opel",       "tags": [         "x1",         "f3"       ]     },     {       "location": "in place two",       "name": "abc",       "tags": [         "a3",         "f5"       ]     }],     "User" :"test"    }  
like image 406
Nico Müller Avatar asked Aug 18 '18 19:08

Nico Müller


People also ask

How to update nested objects in DynamoDB?

To update an item you first need to identify it and get primary key or composite key, if there are many items that match your criteria, you need to update one by one. then the issue to update nested objects is to define UpdateExpression,ExpressionAttributeValues & ExpressionAttributeNames to pass to Dynamo Update Api .

How to update items in DynamoDB?

To update an existing item in an Amazon DynamoDB table, you use the UpdateItem operation. You must provide the key of the item that you want to update. You must also provide an update expression, indicating the attributes that you want to modify and the values that you want to assign to them.

Does Put item update item DynamoDB?

The main difference between the two is, PutItem will Replace an entire item while UpdateItem will Update it.

What is the use of add new attribute method in DynamoDB?

ADD - Causes DynamoDB to create an item with the supplied primary key and number (or set of numbers) for the attribute value. The only data types allowed are Number and Number Set.


2 Answers

Updated Answer - based on updated question statement

You can update attributes in a nested map using update expressions such that only a part of the item would get updated (ie. DynamoDB would apply the equivalent of a patch to your item) but, because DynamoDB is a document database, all operations (Put, Get, Update, Delete etc.) work on the item as a whole.

So, in your example, assuming User is the partition key and that there is no sort key (I didn't see any attribute that could be a sort key in that example), an Update request might look like this:

table.update_item(   Key={     'User': 'test'   },   UpdateExpression="SET #inv[0].#loc = :locVal",   ExpressionAttributeNames={     '#inv': 'inventory',     '#loc': 'location'   },   ExpressionAttributeValues={     ':locVal': 'in place three',   }, ) 

That said, you do have to know what the item schema looks like and which attributes within the item should be updated exactly.

DynamoDB does NOT have a way to operate on sub-items. Meaning, there is no way to tell Dynamo to execute an operation such as "update item, set 'location' property of elements of the 'inventory' array that have a property of 'name' equal to 'opel'"

This is probably not the answer you were hoping for, but it is what's available today. You may be able to get closer to what you want by changing the schema a bit.

If you need to reference the sub-items by name, perhaps storing something like:

{   "inventory": {     "opel": {        "location": "in place one",      # I want to update this        "tags": [ "x1", "f3" ]     },     "abc": {        "location": "in place two",        "tags": [ "a3", "f5" ]     }   },   "User" :"test"  }  

Then your query would be:

table.update_item(   Key={     'User': 'test'   },   UpdateExpression="SET #inv.#brand.#loc = :locVal",   ExpressionAttributeNames={     '#inv': 'inventory',     '#loc': 'location',     '#brand': 'opel'   },   ExpressionAttributeValues={     ':locVal': 'in place three',   }, ) 

But YMMV as even this has limitations because you are limited to identifying inventory items by name (ie. you still can't say "update inventory with tag 'x1'"

Ultimately you should carefully consider why you need Dynamo to perform these complex operations for you as opposed to you being specific about what you want to update.

like image 90
Mike Dinescu Avatar answered Oct 01 '22 05:10

Mike Dinescu


Updating Mike's answer because that way doesn't work any more (at least for me).

It is working like this now (attention for UpdateExpression and ExpressionAttributeNames):

table.update_item(   Key={     'User': 'test'   },   UpdateExpression="SET inv.#brand.loc = :locVal",   ExpressionAttributeNames={     '#brand': 'opel'   },   ExpressionAttributeValues={     ':locVal': 'in place three',   }, ) 

And whatever goes in Key={}, it is always partition key (and sort key, if any).

EDIT: Seems like this way only works when with 2 level nested properties. In this case you would only use "ExpressionAttributeNames" for the "middle" property (in this example, that would be #brand: inv.#brand.loc). I'm not yet sure what is the real rule now.

like image 32
Fabricio Avatar answered Oct 01 '22 06:10

Fabricio