Home > Back-end >  Python nested dictionaries - Append data to nested dict without overwriting previous data
Python nested dictionaries - Append data to nested dict without overwriting previous data

Time:10-10

async for document in client.auto_role.find({}):
    if client.auto_role_cache.get(document.get("guildID")):
        client.auto_role_cache[document.get("guildID")]["roles"] = {document.get("roleID"): document.get("delay")}
    else:
        client.auto_role_cache[document.get("guildID")] = {"roles": {document.get("roleID"): document.get("delay")}}

Hey, just wondering how if the guildID is in the dict, (meaning there are already roles in the dict) how I can add more roles into it, without deleting the old ones? The code block above replaces the old data with the new data.

guildID {roles: {roleID1: delayHere, roleID2: delayHere}

Do you have to overwrite the entire dict every time you want to add new data? Or is there something similar to .append in a list?

Surely, I wouldn't have to get the old data, and then add it with the new data every time I want to add new things into the nested dict? That seems very inefficient?

CodePudding user response:

Before you can store multiple data, you may need to reconsider the structure based on which the data is stored. Currently, the roles field is just an object which which re-assigned replaces the old data. In order to get the expected behavior, i.e., storing multiple roles, you would have to store a list of objects instead.

So, effectively

{"roles": {...}}

is converted to something like:

{"roles": [{...}, {...}, ...]}

As you can see, now you can store multiple roles under the roles field. After you fix the structure of the document as specified, you may edit the code-block under if statement like so:

# Create a new role
new_role = {document.get("roleID"): document.get("delay")}

# Append the new role to the list
client.auto_role_cache[document.get("guildID")]["roles"].append(new_role)

EDIT: Based on the edits made to the question, you seem to have different roleIDs. In this case, you do not need to change the structure of the data. All you need to do is add a new field to the roles dictionary. You can use plain old indexing to get that working.

The edited code would be something like:

# Get the new role ID and delay
role_id = document.get("roleID")
delay = document.get("delay")

# Append the new role to the list
client.auto_role_cache[document.get("guildID")]["roles"][role_id] = delay

In the above code snippet, we are setting the role_id field to newly fetched delay value by using the dictionary[key] = value construct.

CodePudding user response:

Keys for items in dict must be unique, so the example you give in the second block of code is impossible.

If you want to store multiple roles in guildID[roles], make the value of that a list, which you can then append to or update as you wish.

A useful function here to ensure that you create the list if you don't have roles in a specific dict is dict.setdefault:

>>> guildID = {}
>>> guildID
{}
>>> guildID.setdefault("roles", []).append("my_role")
>>> guildID.setdefault("roles", []).append("my_role2")
>>> guildID
{'roles': ['my_role', 'my_role2']}
>>> 

EDIT: Based on the updates to the question, you might want instead:

>>> guildID = {}
>>> guildID.setdefault("roles", {})["my_role"] = 123
>>> guildID.setdefault("roles", {})["my_role2"] = 123
>>> guildID
{'roles': {'my_role': 123, 'my_role2': 123}}

This means you don't have to create a special case for the first role you add to also create dict roles in guildID.

  • Related