Nico Müller
Nico Müller

Reputation: 1874

dynamodb/python updateitem append item in nested map

How can I append an item to an existing map in dynamodb I want to add a new set of location/name/tags.

The structure in dynamodb looks like the below

{  
"user": "xyz",   
"itemdetails": [
    {
      "location": "67666",
      "name": "item1",
      "tags": [
        "k7866"
      ]
    },
    {
      "location": "45444",
      "name": "item12",
      "tags": [
        "ha23",
        "ju4532"
      ]
    }
}

I tried the below but get a

"Invalid UpdateExpression: Incorrect operand type for operator or function; operator: ADD, operand type: MAP"

response = table.update_item(
    Key={
        'user': "xyz",
    },
    UpdateExpression = 'ADD #itemdetails :newItems',
    ExpressionAttributeNames = {
      '#itemdetails' : 'ids'
    },
    ExpressionAttributeValues = {
      ':newItems' : {"name":name, 
         "location":location,
         "tags":tags
        }
    },
    ReturnValues="UPDATED_NEW"

Upvotes: 2

Views: 2029

Answers (2)

Dinesh Sonachalam
Dinesh Sonachalam

Reputation: 1379

I'm the author of Lucid-Dynamodb, a minimalist wrapper to AWS DynamoDB. This problem can be easily solved using this python library.

Reference: https://github.com/dineshsonachalam/Lucid-Dynamodb#8-add-an-attribute-to-the-list

from LucidDynamodb.Operations import DynamoDb
import os
import logging
logging.basicConfig(level=logging.INFO)

AWS_ACCESS_KEY_ID = os.getenv("AWS_ACCESS_KEY_ID")
AWS_SECRET_ACCESS_KEY = os.getenv("AWS_SECRET_ACCESS_KEY")

table_schema = {
    "TableName": "test",
    "KeySchema": [
        {
            "AttributeName": "user",
            "KeyType": "HASH"
        }
    ],
    "AttributeDefinitions": [
        {
            "AttributeName": "user",
            "AttributeType": "S"
        }
     ],
    "GlobalSecondaryIndexes": [],
    "ProvisionedThroughput": {
        "ReadCapacityUnits": 1,
        "WriteCapacityUnits": 1
    }
}


if __name__ == "__main__":
    
    # 1. create a new table
    db = DynamoDb(region_name="us-east-1", 
                aws_access_key_id=AWS_ACCESS_KEY_ID, 
                aws_secret_access_key=AWS_SECRET_ACCESS_KEY)
                
    table_creation_status = db.create_table(
                                    TableName=table_schema.get("TableName"),
                                    KeySchema=table_schema.get("KeySchema"),
                                    AttributeDefinitions=table_schema.get("AttributeDefinitions"),
                                    GlobalSecondaryIndexes=table_schema.get("GlobalSecondaryIndexes"),
                                    ProvisionedThroughput=table_schema.get("ProvisionedThroughput")
    )
    if(table_creation_status == True):
        logging.info("{} table created successfully".format(table_schema.get("TableName")))
    else:
        logging.error("{} table creation failed".format(table_schema.get("TableName")))
    
    # 2. Create a new item
    item_creation_status = db.create_item(
        TableName=table_schema.get("TableName"), 
        Item =  {
            "user": "xyz",
            "itemdetails": [{
                    "location": "67666",
                    "name": "item1",
                    "tags": [
                        "k7866"
                    ]
                },
                {
                    "location": "45444",
                    "name": "item12",
                    "tags": [
                        "ha23",
                        "ju4532"
                    ]
                }
            ]
        }
    )
    if(item_creation_status == True):
        logging.info("Item created successfully")
    else:
        logging.warning("Item creation failed")
        
    
    # 3. Add/Append an attribute to the list
    item_update_status = db.update_item(
        TableName=table_schema.get("TableName"), 
        Key={
            "user": "xyz"
        },
        AttributesToUpdate={
            "itemdetails": {
                    "location": "333",
                    "name": "item3",
                    "tags": [
                        "tag333"
                    ]
                }
        },
        Operation="ADD_ATTRIBUTE_TO_LIST"
    )
    if(item_update_status == True):
        logging.info("Update is successful")
    else:
        logging.warning("Update failed")

    item = db.read_item(
        TableName=table_schema.get("TableName"), 
        Key={
            "user": "xyz"
        })
    if(item != None):
        logging.info("Item: {}".format(item))
    else:
        logging.warning("Item doesn't exist")

**Output: **

dineshsonachalam@macbook Dynamodb-experiment % python test.py
INFO:root:test table created successfully
INFO:root:Item created successfully
INFO:root:Update is successful
INFO:root:Item: 

{
    'itemdetails': [{
        'name': 'item1',
        'location': '67666',
        'tags': ['k7866']
    }, {
        'name': 'item12',
        'location': '45444',
        'tags': ['ha23', 'ju4532']
    }, {
        'name': 'item3',
        'location': '333',
        'tags': ['tag333']
    }],
    'user': 'xyz'
}

Upvotes: 2

Nico Müller
Nico Müller

Reputation: 1874

I solved it now with

 UpdateExpression = 'SET itemdetails = list_append(itemdetails, :newitem)',
        ExpressionAttributeValues={
            ":newitem": [
                    {
                        "name":"TEST", 
                        "location":"TEST",
                        "tags":tags
                    }
            ]
        },
        ReturnValues="UPDATED_NEW"
    )

Upvotes: 3

Related Questions