A common programming concept that we have not covered with Solidity yet is data associations. While in many languages there are multiple ways to associate values, in Solidity there is only one way to do that, which is by using a mapping data type. Solidity mappings behave like hash tables found in object-oriented programming languages. The mapping() data type accepts a key that is mapped to a value.
mapping(_KeyType => _ValueType) public mapping_label
example
mapping(address => string) public app_username
Using a mapping creates value associations in memory that can be visualized like the virtual table below.
There are no length limits with mappings and you cannot iterate through a mapping. The reason why you cannot loop through mappings is because they do not store the keys, they only store the hashed value in the state memory. Because the key is not stored, there is no way for a contract to discover the mapped data. The only way you can look up the values are if you have the original key.
CRUD
Creating, reading, updating, and deleting a mapping start by passing the key value in square brackets, [ ]
, after calling the name given to the mapping. Reading a mapping only requires the key value. Creating/updating actions require the key value and are set using an equal sign and then the value the key should be set to. The delete action uses the reserved delete
keyword before the mapping reference.
Create/Update
app_username[msg.sender] = ‘Connor’ // Sets the string ‘Connor’ as an association to the sender address
Read
app_username[msg.sender] // Returns ‘Connor’
Delete
delete app_username[msg.sender] // Deletes the value its association to the sender address
Nested
Mappings can also be nested, creating a similar pattern to a one-to-many relationship in a database. In order to nest a mapping, you need to declare a mapping as the value in the mapping. This will map the key in the previous mapping to a value that is another mapping and its mapping value. Creating, reading, updating, and deleting actions follow the same methodology as a regular mapping.
mapping(_KeyType => mapping(_KeyType => _ValueType) public nested_mapping_label
example
mapping(address => mapping(address => string) public tribe
In order to call the value in the nested mapping, you have to pass both key layers by using two square brackets references.
tribe[msg.sender][secondAddress]
Mapping Arrays
Arrays can also be used in mappings. To use an array in a mapping, declare an array in the _ValueType portion of the mapping.
mapping(address => uint[]) public stock;
By setting an array as the value, you pass the array methods to mapping calls.
Adding to a mapped array
stock[msg.sender].push(1); // Store 1 as an element in the array
Read the value at the first index in the array
stock[msg.sender][0]; // Returns 1
Set the value at the second index in the array to 10
stock[msg.sender][1] = 10; // Sets the value of 10 as at the first index in the array
Delete the second index in the array
delete stock[msg.sender][1]; // Deletes the value at the second index in the array. In this case that would be the value 10
Utility by Association
Mapping’s are a great data type to use when you need to store entries with an association to a specific key. There are no other data types that create associations. They are flexible in the sense that they don’t have a length limit and can accept various data types including mappings and arrays, but limited by the way that they are not iterable and require knowledge of the key value in order to take any action for that mapping. Keep this in mind when determining the architecture of your contract and if there is a need for mapping.