8

In the contract multi index tables we can filter by the primary key or we can just create an indexed_by as an additional index.

Then we have basically two options: filter by the primary key or filter by the additional index.

But what if we want to add a second additional index and find for both of them?

Like in a SQL fashion: index1 = 1 AND index2 = 2

I've already asked this question and received the below answer from Dan Larimer, in Official EOS Developers Telegram, but I'm sharing with you because I believe it can help others

10

So, for this scenario we can create another index that concatenates both indexes and look for it. As an example, let's see a scenario where we can invite accounts to a group and each invitation has an id.

// table declaration for invites 
// @abi table invitation i64
struct invitation {
    uint64_t     id;
    uint64_t     group;
    account_name user;

    uint64_t primary_key() const { return id; }

    uint128_t get_user_by_group() const { return combine_ids(group, user); }

    EOSLIB_SERIALIZE(invitation, (id)(group)(user))
};
typedef multi_index<N(invitation), invitation, 
  indexed_by<N(user_by_group), const_mem_fun<invitation, uint128_t, 
                              &invitation::get_user_by_group>>
> tb_invitation;

// concatenation of ids example
uint128_t combine_ids(const uint64_t &x, const uint64_t &y) {
    return (uint128_t{x} << 64) | y;
}


// now in your smartcontract, you can look if the user already
// belongs to the specific group
// validates if user is already in the community

tb_invitation invitation(_self, _self);
auto idx_existent_invitation = invitation.template get_index<N(user_by_group)>();
auto group_user_id = combine_ids(group_id, new_user_id);
auto itr_group_user = idx_existent_invitation.find(group_user_id);
eosio_assert(itr_group_user == idx_existent_invitation.end(), 
    "user already invited to group");

Besides that, you can also do Dan's suggestion, using two iterators and merging them. This solution works for simple AND clauses only. Dan suggestion's would probably be better for OR and any other complex filters.

Also, it was my own implementation without Dan eyes, if you can, please suggest any improvements and better approaches on this concatenation! ;)

| improve this answer | |
  • 3
    combine_ids doesn't need a loop. Try (uint128_t{x} << 64) | y. – Todd Fleming May 8 '18 at 17:42
  • Thanks @ToddFleming ! I tested and it worked perfectly! EDITED! – Leo Ribeiro May 8 '18 at 17:48
  • What is group_id & new_user_id? – abhi3700 Aug 16 at 5:30

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.