0

I am trying to create a new map and also assign it a new value at the same time

This is the data format I want to store in my db:

{
    "user_id": 1,
    "project_id": 1,
    "MRR": {
         "NICHE": {
             "define your niche": {
                   "vertical": "test",
                   "ideal prospect": "He is the best"
             }
         },
         "Environment": {
             "Trend 1": {
                   "description": "something"
             },
             "Trend 2": {
                   "description": "something else"
             }
         }

    }

}

My code so far for inserting data is:

def update_dynamo(user_id, project_id, group, sub_type, data):
    dynmoTable.update_item(
        Key = {
            "user_id": user_id
        },
        ConditionExpression=Attr("project_id").eq(project_id),
        UpdateExpression="SET MRR.#group = :group_value",
        ExpressionAttributeNames={
            "#group": group
        },
        ExpressionAttributeValues={
            ":group_value": {}
        }
    )

    dynmoTable.update_item(
        Key={
            "user_id": user_id
        },
        ConditionExpression=Attr("project_id").eq(project_id),
        UpdateExpression="SET MRR.#group.#subgroup = :sub_value",
        ExpressionAttributeNames={
             "#group": group,
             '#subgroup': sub_type
        },
        ExpressionAttributeValues={
             ":sub_value": data
        }
     )
data = {
    "description": "world",
}
if __name__ == "__main__":
    update_dynamo(1, 1, "New Category", "Hello", data)

My question is can these 2 update_items somehow be merged into one?

1 Answer 1

1

Sure, you can assign to the top-level attribute an entire nested "document", you don't need to assign only scalars.

Something like this should work:

    dynmoTable.update_item(
        Key = {
            "user_id": user_id
        },
        ConditionExpression=Attr("project_id").eq(project_id),
        UpdateExpression="SET MRR.#group = :group_value",
        ExpressionAttributeNames={
            "#group": group
        },
        ExpressionAttributeValues={
            ":group_value": {sub_type: sub_data}
        }
    )

Note how you set the "group" attribute to the Python dictionary {subtype: sub_data}. boto3 will convert this dictionary into the appropriate DynamoDB map attribute, as you expect. You can set sophisticated nested dictionaries, lists, nested in each other this way - in a single update.

Sign up to request clarification or add additional context in comments.

3 Comments

The problem is that when I do your solution it erases the existing data inside an existing map. I would like to also append the data if the "group" already exists.
Oh... In your original question, both the example code you wished to replace, and the text, described replacing whatever MRR.group was by a new map with specific content... Not appending. Appending is a different and more interesting question, and I don't know the answer to it. With a list you can do it, e.g., SET a = list_append(if_not_exists(a, :empty), :val2). Unfortunately, I can't think of a similar function which would work for a map; Also you are not allowed to do two SETS to the same attribute in the same expression.
Yes sorry for misunderstanding. My solution was to create all the groups (Thankfully in my case they are fixed) so I can use the SET expression easily to add maps to each group. Thanks for taking time to answer!

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.