6

This question addresses how a value stored in a contract variable from the outside.

Is there any similar way to access a value of tuples stored in mapping(with and without knowing a key of mapping).

Consider the following smart contract.

pragma solidity ^0.4.24;
contract Student{
    struct stu{
        string name;
        uint age;
        bool tookTest;
    }
    mapping(uint => stu) studentNames;
    function addStudent (uint ID, string _name, uint _age) {
        studentNames[ID] = stu(_name, _age, false);
    }
    function updateStudent (uint ID) {
        studentNames[ID].tookTest = true;
    }
}

I want to all the tuples stored in studentNames and I know only contract address.

Is that possible?

2
  • A mapping maps all possible keys, so you cannot get just the values which you have explicitly added, without knowing the keys which you have explicitly used. In order to achieve that, every time you add a value, you need to store the key in an array (but ideally, only if it's the first time that you are using this key). Sep 4, 2018 at 14:57
  • If you also plan to delete values from the mapping, then you need to scan the array and delete the appropriate key (or you can establish a more sophisticated data-structure which will allow you to delete the key from the array in a constant number of operations - if you want this solution, then I've got one ready). Sep 4, 2018 at 14:57

2 Answers 2

4

You can do it if you add one array to store the mapping key; then you can return the key array to client, and client can iterate keys to get the student information for each key.

6
  • Can you share commands/code to iterate keys Sep 4, 2018 at 13:43
  • You need to write a function on smart contract to return the key array to client; then you can use javascript to iterate the returned array from smart contract.
    – Tony Dang
    Sep 4, 2018 at 13:45
  • I don't want to use arrays to store keys and my mapping is private(I have modified a code). Is there any possibility to access mapping outside a contract? Sep 4, 2018 at 13:59
  • you can read smart contract storage by using rpc api medium.com/aigang-network/…
    – Tony Dang
    Sep 4, 2018 at 14:04
  • Ha Dang is correct. You cannot enumerate the keys in a mapping because all keys exist. You can either a) track keys in an array, or you can b) externalize the requirement, meaning dismiss it completely. It is recommended to emit events for all important state changes. Having done so, it would then be possible for an observing software client to know all the keys without inspecting the contract state. This method does not work for other contracts, which brings us back to storing an index. Sep 4, 2018 at 14:10
5

A mapping maps all possible keys, so you cannot get just the values which you have explicitly added, without knowing the keys which you have explicitly used. In order to achieve that, every time you add a value, you need to store the key in an array (but ideally, only if it's the first time that you are using this key).

If you also plan to delete values from the mapping, then you need to scan the array and delete the appropriate key, or you can establish a more sophisticated data-structure which will allow you to delete the key from the array in a constant number of operations.

For example:

pragma solidity ^0.4.24;

contract StudentManager {
    uint[] public studentList;

    struct Student {
        bool valid;
        uint index;
        string name;
        uint age;
        bool tookTest;
    }

    mapping(uint => Student) public students;

    /* Update or insert a student */
    function upsert(uint ID, string _name, uint _age, bool _tookTest) external {
        Student storage student = students[ID];
        if (!student.valid) {
            student.valid = true;
            student.index = studentList.length;
            studentList.push(ID);
        }
        student.name = _name;
        student.age = _age;
        student.tookTest = _tookTest;
    }

    /* Remove a student */
    function remove(uint ID) external {
        Student storage student = students[ID];
        require(student.index < studentList.length);
        require(ID == studentList[student.index]);
        uint lastStudent = studentList[studentList.length - 1];
        students[lastStudent].index = student.index;
        studentList[student.index] = lastStudent;
        studentList.length -= 1;
        delete students[ID];
    }

    /* Get the total number of students */
    function studentCount() external view returns (uint) {
        return studentList.length;
    }
}

Your Answer

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

Not the answer you're looking for? Browse other questions tagged or ask your own question.