With your currently defined variables, you can loop through all the existing store items until you've found the corresponding item, and then update it. If there's no corresponding item, you can create a new one:

function addProduct(uint id,  uint quantity) public {
    // loop through all `store` items until the item with the corresponding ID is found
    for (uint i; i < store.length; i++) {
        if (store[i].id == id) {
            // corresponding item found - update quantity and early return
            store[i].quantity += quantity;
            return;
        }
    }

    // no corresponding item found (the early return didn't invoke) - add the product to the store
    store.push(Store(id, quantity));
}

However, the code above is very inefficient and expensive to run gas-wise. So I'd recommend to add a mapping of existing product IDs to the store array indexes. Then you can simply query the mapping and get the resulting info whether the product ID exists (the value of the mapping is non-zero) or not:

mapping (uint => uint) productIdToArrayIndex;

function addProduct(uint id,  uint quantity) public {
    uint arrayIndex = productIdToArrayIndex[id];
    if (arrayIndex > 0) {
        // the product is stored in the `store[arrayIndex]`
        store[arrayIndex].quantity += quantity;
    }

    // no corresponding item found - add the product to the store, and add their index to the mapping
    store.push(Store(id, quantity));
    productIdToArrayIndex[id] = store.length - 1;
}
Answer from Petr Hejda on Stack Overflow
Discussions

solidity - How to check if an array key exists? - Ethereum Stack Exchange
Very smart, thank you! Even though, this only helps if you have Struct values. What about basic types? ... Basic types can always be wrapped in a struct. Or you could have a separate bool[] exists. There's no concept of "existence" in Solidity: just zeros and non-zeros. More on ethereum.stackexchange.com
๐ŸŒ ethereum.stackexchange.com
August 10, 2018
mapping - Solidity 0.4.26 check if element already exists in array - Ethereum Stack Exchange
Note: The called function should be payable if you send value and the value you send should be less than your current balance. Debug the transaction to get more information. I've tried changing the array to a string as the single user can have multiple data entries but its still giving me the ... More on ethereum.stackexchange.com
๐ŸŒ ethereum.stackexchange.com
June 9, 2020
ethereum - How to know if a specific value exists in the mapping table or not? - Stack Overflow
I have a mapping table whcich stores multiple hashes into that table. What I want to do is that I want the user to add another hash with setinstructors() function and then try to look whether the s... More on stackoverflow.com
๐ŸŒ stackoverflow.com
solidity - How to efficiently check if items in array A exist in array B? - Ethereum Stack Exchange
I need to compare 2 uint256[]'s checking if the items in one array exist in the second array. Would love declare a mapping (uint256 => bool) exists within the function and loop through the second More on ethereum.stackexchange.com
๐ŸŒ ethereum.stackexchange.com
September 17, 2022
๐ŸŒ
Whole Blogs
wholeblogs.com โ€บ home โ€บ how to check if value exists in array using solidity
How to Check If Value Exists In Array Using Solidity - Whole Blogs
January 11, 2022 - pragma solidity ^0.5.0; &amp;nbsp; contract test { function testArray() public pure{ uint len = 7; //dynamic array uint[] memory a = new uint[](7); //bytes is same as byte[] bytes memory b = new bytes(len); assert(a.length == 7); assert(b.length == len); //access array variable a[6] = 8; //test array variable assert(a[6] == 8); //static array uint[3] memory c = [uint(1) , 2, 3]; assert(c.length == 3); } }
Top answer
1 of 2
1

In order to avoid For loops, You can add another mapping to check if a user exists or not. You can add mapping(string => bool) userExists; so your whole code will look like this:

pragma experimental ABIEncoderV2;


contract structWithMapping{

    struct Data{
        string[] user;
        string[] catagory;
        string[] data;
    }


    mapping(string => Data) mappedData;
    mapping(string => bool) userExists;

    string[] public dataArray;

    function setUserData(string _user, string _catagory, string _data)public{
        var addData = mappedData[_user];


        addData.user.push(_user);
        addData.catagory.push(_catagory);
        addData.data.push(_data);

        require(!userExists[_user]);
        dataArray.push(_user) -1;
        //dont forget to set the mapping value to true for userExists
        userExists[_user] = true;
    }

    function getUsers() view public returns(string[]){
        return dataArray;
    }

    function getUserData(string _user) view public returns(string[] memory, string[] memory, string[] memory){
        return(mappedData[_user].user, mappedData[_user].catagory, mappedData[_user].data);
    }
}
2 of 2
1

Reading your code I think I understood what you want to achieve, but I suggest to completely change the approach. Please note that using a smart contract costs money, so as a developer you should aim to create business logic that is both clean - so it cannot be misinterpreted or misleading - and light - so every transaction costs as few as possible.

To achieve that you need also to deep dive into the EVM and Solidity or Vyper.

That said, I think your entire smart contract should be transformed to this:

contract structWithMapping {

    struct User {
        string  username;
        string  category;
        string  data;
        bool    initialized;
    }
    mapping(string => User) public users;

    function setUserData(string memory _username, string memory _category, string memory _data) public{
        require(!users[_username].initialized);
        users[_username].username = _username;
        users[_username].category = _category;
        users[_username].data = _data;
        users[_username].initialized = true;
    }

}

Note also that Solidity adds getter functions at compile time for every public variable, so in this case a users function will be created. You can use that function passing the username as parameter to retrieve user data in the exact same way you would have called getUserData function.

I created a gist so you can directly experiment through the Remix IDE via this link.

๐ŸŒ
Cloudhadoop
cloudhadoop.com โ€บ home
How to check value or object exists in Solidity mapping?
March 10, 2024 - Unlike other languages (Java, JavaScript), there is no null or undefined in Solidity. Values are assigned to zero bytes if there is no object. If a reference type exists, such as an array or struct, the values default to the zero byte representation.
Find elsewhere
๐ŸŒ
Moralis
studygroup.moralis.io โ€บ ethereum smart contract programming 101
Verify if value exists in an array - Ethereum Smart Contract Programming 101 - Moralis Academy Forum
April 1, 2021 - Hi! My question is related to how we can verify if a value exists in an array without using loops like other normal languages in order to avoid elevated gas costs. For example I provide an array of addresses and I need to check if an specific address its included in this array. arrayOfAddress = [address1,address2,address3]; address addressToFound = someRandomAddress; addresToFound exists in arrayOfAddress ??
๐ŸŒ
Medium
medium.com โ€บ coinmonks โ€บ array-and-map-in-solidity-a579b311d74b
Arrays and Maps in Solidity. An array allows us to represent aโ€ฆ | by Agoi Abel | Coinmonks | Medium
June 24, 2022 - We can read a value, update a value, ... array as a function argument in solidity, the function visibility determines if the keyword before the array name should be calldata or memory....
๐ŸŒ
Reddit
reddit.com โ€บ r/ethereum โ€บ how can you figure out if a certain key exists in a mapping (in solidity)?
r/ethereum on Reddit: How can you figure out if a certain key exists in a mapping (in Solidity)?
September 1, 2015 -

In Javascript, we might check for the existence of an object member like this:

if (object[key]) {
  // do something
} else {
  // do something else
}

I tried if(mapping[key]) { ... } in Solidity but that didn't work...

"Note that there is no type conversion from non-boolean to boolean types as there is in C and JavaScript, so if (1) { ... } is not valid Solidity." (https://github.com/ethereum/wiki/wiki/Solidity-Tutorial#control-structures).

mapping[key] == 0 is not a valid expression, so... how do we check for the existence of a key in a mapping?

Top answer
1 of 2
13

Solidity provides no obvious way to do this.

One can contemplate an iterative process to search the list, but the gas cost will increase with the size of the list. This puts an upper bound on the size of the list; either by increasing transaction cost to an unacceptable level, or by exceeding the block gas limit so transactions can't run at all.

There are (at least) two general solutions.

  1. Invert control so the client performs the iterative operation and interrogates contract functions one row at a time. It's possible to expose indexed lists (searchable) with event emitters. That may help, but in any case, performance will suffer with list size.

  2. Use a mapping to facilitate random access in a single step.

Since mappings can't be enumerated and it's not possible to know how many keys have been set or what they are, it may be necessary to devise a system of pointers using both arrays and mappings to produce a "list" of randomly accessible items.

Have a look here for a pattern and better explanation: https://bitbucket.org/rhitchens2/soliditycrud/overview

Hope it helps.

2 of 2
0

In case someone still wants a solution to identify a string inside an array.

You first need to have a way to compare strings. You can do it using the following function:

// Function to compare 2 strings
    function compareStrings(string memory firstString, string memory secondString) internal pure returns (bool) {
      return keccak256(bytes(firstString)) == keccak256(bytes(secondString));
    }

This will return true if the 2 inputs match.

Then we can use this function to iterate in the array and check if the string exists:

function findString(string[] memory array,string memory _string) internal pure returns (bool){
    for (uint i = 0; i < array.length; i++) { 
        string memory stringToFind = array[i]; 
        bool exists = compareStrings(stringToFind, _string) ;
        if(exists == true) {
            return true;

        }   
    }
        return false;
    }

This will return true if the string is in the array and false if it isn't.

You can then use it like this:

//SPDX-License-Identifier: MIT

pragma solidity ^0.8.0;

contract FindString {

    string[] public colors = ["blue", "yellow", "red"];

    function compareStrings(string memory firstString, string memory secondString) internal pure returns (bool) {
      return keccak256(bytes(firstString)) == keccak256(bytes(secondString));
    }


    function findString(string[] memory array,string memory _string) internal pure returns (bool){
    for (uint i = 0; i < array.length; i++) { 
        string memory stringToFind = array[i]; 
        bool exists = compareStrings(stringToFind, _string) ;
        if(exists == true) {
            return true;

        }   
    }
        return false;
    }


    function findStringInArray(string memory _string) public view returns(bool){
        return findString(colors, _string);
    }

}

I also made a Solidity library to help with these kind of tasks:

  • Soliditool
๐ŸŒ
Stack Exchange
ethereum.stackexchange.com โ€บ questions โ€บ 131715 โ€บ how-to-test-if-array-contains-any-value
solidity - how to test if array contains any value? - Ethereum Stack Exchange
July 14, 2022 - if I tried to access people array's 0th index through hardhat like this ยท let peopleArray = await simpleStorage.people("0"); console.log(`People ${peopleArray}`); ... Error: call revert exception [ See: https://links.ethers.org/v5-errors-CALL_EXCEPTION ] (method="people(uint256)", data="0x", errorArgs=null, errorName=null, errorSignature=null, reason=null, code=CALL_EXCEPTION, version=abi/5.6.4) at Logger.makeError (E:\Learning_Programming\Solidity\SimeplStorageHardHat\node_modules\@ethersproject\logger\src.ts\index.ts:261:28) at Logger.throwError (E:\Learning_Programming\Solidity\SimeplStora
๐ŸŒ
DEV Community
dev.to โ€บ fassko โ€บ leveraging-the-set-structure-in-solidity-1n7
Leveraging the Set Structure in Solidity - DEV Community
July 26, 2023 - This function can come in handy if we want to understand if the Set holds anything at all and if we're going to iterate over it ourselves. Solidity programming language does not have a built-in Set data structure. However, we can solve this issue by merging two existing Solidity structures - arrays and mappings. This approach enables us to build all the functions of a Set, such as adding unique elements, removing them, checking for their presence, and listing all current elements.
Top answer
1 of 3
1

Have a look here: Are there well-solved and simple storage patterns for Solidity?

You could.

function isMember(uint index) public view returns(bool isIndeed) {
  return members[index].exists;
}

It's preferable to throw an error on an unacceptable state change rather than return false in most situations. So ...

function addBalance(uint index) public returns(bool success) {
  require(isMember(index);
  members[index] += msg.value; // (or _balance if you prefer)
  return true;
}

If there is a good reason to return false and carry on:

function addBalance(uint index) public returns(bool success) {
  if(!isMember(index) return false;
  if(isMember(index)) member[index] += msg.value;
  return true;
}

In my opinion it's almost always better to use the member address as the key instead of storing the structs in numbered rows. Like that, using arbitrary amounts instead msg.value as in your example:

pragma solidity ^0.4.24;

contract MembersContract {

    struct Member {
        uint balance;
        bool exists;
    }

    mapping(address => Member) public members;

    function isMember(address member) public view returns(bool isIndeed) {
        return members[member].exists;
    }

    function addMember(address member) public returns(bool success) {
        require(!isMember(member));
        members[member].exists = true;
        return true;
    }

    function addBalance(address member, uint amount) public returns(bool success){
        require(isMember(member));
        members[member].balance += amount;
        return true;
    }
}

Hope it helps.

2 of 3
0

Array access is guarded in Solidity. If you try to read past the end of the array, you'll get an invalid opcode error.

If you want to catch this condition yourself, you could do a bounds check first:

if (members.length > 1 && members[1].exists) {
    ...
}