0

In the code here, I have created a new Customer called "mcycleowner", and mapped it to an input _address. However, I also want to map it to the input _license so that customer info can be queried with either an Eth address or license plate number.

To do so, I created a new Customer "mcyclelicenses", and the function addLicense takes the same inputs as newMcycleOwner (except address), only this Customer is mapped to _license. This function is triggered within the "newMcycleOwner" function so that both customers and mappings are created simultaneously.

However, doing it this way means having two records of each customer's information, which seems like it would be a waste of space, and also whenever customer info needs to be changed, it will have to be changed in two places. Is there a better way to do this?

// < ---------------------- MOTORCYLCES ---------------------- >


mapping (address => Customer) mcycleowners;
address[] public mcycleownerAdds;


function newMcycleOwner(address _address, string _custname, string _color, string _make, uint32 _year, string _license) onlyMember public {

    Customer storage mcycleowner = mcycleowners[_address];
        mcycleowner.custname = _custname;
        mcycleowner.color = _color;
        mcycleowner.make = _make;
        mcycleowner.year = _year;
        mcycleowner.license = _license;

        mcycleownerAdds.push(_address);

    addLicense(_custname, _color, _make, _year, _license);
}

    function getMcycleAdds() public view returns(address[]) {
        return mcycleownerAdds;
    }

    function getMcycleByAdd(address _address) public view returns(string, string) {
        return (mcycleowners[_address].custname, mcycleowners[_address].license);
    }

    function countMcycle() public view returns(uint) {
        return mcycleownerAdds.length;
    }


// <---------- CREATION OF NEW MAP SO WE CAN QUERY BY LICENSE ---------->

//This seems to create two instances of each customer.  Replace with a better method.

mapping (string => Customer) mcyclelicenses;

function addLicense(string _custname, string _color, string _make, uint32 _year, string _license) onlyMember public {
    Customer storage mcyclelicense = mcyclelicenses[_license];
        mcyclelicense.custname = _custname;
        mcyclelicense.color = _color;
        mcyclelicense.make = _make;
        mcyclelicense.year = _year;

}

 function getMcycleByLic(string _license) public view returns(string, string, string, uint32) {
    return (mcyclelicenses[_license].custname, mcyclelicenses[_license].color, mcyclelicenses[_license].make, mcyclelicenses[_license].year);
}
0

An easy way to do it could be to save the customers info inside an array and use the mapping to store the indexes of the array so that you will access directly to the index through the mapping and use this index to access directly to the array.

Here an example

pragma solidity ^0.4.23;

contract ContractX {
    struct Customer {
        string name;
        string license;
        /* other infos */
    }

    mapping (address => uint) addressIndexes;
    mapping (string => uint) licenseIndexes;
    Customer[] customers;
    uint customerCount;

    function addNewItem(address _address, string _name, string _license) public {
        customers.push(Customer(_name, _license));

        addressIndexes[_address] = customerCount;
        licenseIndexes[_license] = customerCount;

        customerCount++;
    }

    function getByAddress(address _address) public view returns(string, string) {
        return (
            customers[addressIndexes[_address]].name, 
            customers[addressIndexes[_address]].license
        );
    }

    function getByLicense(string _license) public view returns(string, string) {
        return (
            customers[licenseIndexes[_license]].name, 
            customers[licenseIndexes[_license]].license
        );
    }
}

So the customer information has been saved only once and you track only the array index into the mapping so that you case use it later to access directly to the customer you need.

Another solution might be to use the Customer as a sub-contract, then create the contract when you add your customer info, and store the address to this new contract into your mappings. But that open another scenario, and you may need to do multiple changes.

  • Ah, this is great. Being still quite new to Solidity, I hadn't realized yet that I could return specific items from an array (just that I could return the entire array or the array length). I will be trying this out. Thanks! – CreatedAMadman Jun 2 '18 at 1:57
0

You can simply map the licence to an address, and then do two lookups to dereference a licence.

mapping(string => address) mcyclelicences;

function getMcycleByLic(string _license) public view returns(string, string, string, uint32) { 
  return (
    mcycleowners[mcyclelicenses[_license]].custname,
    mcycleowners[mcyclelicenses[_license]].color,
    mcycleowners[mcyclelicenses[_license]].make,
    mcycleowners[mcyclelicenses[_license]].year
  );      
}
  • This is quite interesting and seems to be a great short cut. I will be trying out both soon. Thank you! – CreatedAMadman Jun 2 '18 at 1:58

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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