Advanced EOS Series — Part 3 — Secondary Indexes

we can define our multi-index table using the multi_index<TABLE_NAME, TABLE_STRUCT> method from the EOS library;typedef multi_index<N(items), Item> items_table;After our typedef, we can simply define a reference and then initialize our table in our constructor, or we can initialize a reference within each function as we need it.Secondary IndexesLet’s expand the functionality of our table by adding a secondary index to fetch items by their respective owner..Our Item struct will now look like;// @abi table items i64struct Item { auto id; string name; uint64_t attack; account_name owner; auto primary_key() const { return id; }; uint64_t get_owner() const { return owner; }; EOSLIB_SERIALIZE(Item, (id)(name)(attack)(owner));};I’ve added the line unit64_t get_owner() const { return owner; }; below our primary_key index..This function simply returns the value for owner when called.Defining the Secondary IndexLet’s define this as a secondary index in our multi-index table so we can access it later;typedef multi_index<N(items), Item, indexed_by<N(byowner), const_mem_fun<Item, uint64_t, &Item::get_owner>>> item_table;Don’t let that line scare you, it’s just our previous declaration with one additional argument.indexed_by<N(byowner), const_mem_fun<Item, uint64_t, &Item::get_owner>>This is the line which defines our secondary index..We’re using the indexed_by<INDEX_NAME, LOOKUP_FUNCTION_DEFINITION> to specify the index namedbyowner.INDEX_NAME; can be whatever you like and doesn’t need to syntactically match our function get_owner, just remember it’s the name we will use to access the secondary index later in our actions.LOOKUP_FUNCTION_DEFINITION: which looks like cons_mem_fun<STRUCT, RETURN_VALUE, LOOKUP_FUNCTION> in our example, constructs our secondary index function and assigns it to the function of our index definition.Using the Secondary IndexSo we’ve indexed our item’s owner, but how can we use our index to find items owned by a particular user?.For this we will be stepping into an action and using the multi-index table method get_index<INDEX_NAME>(), let’s create an action called inventory to fetch a users items.// @abi actionvoid inventory(const account_name account) { item_table items(_self, _self); auto playerItems = items.get_index<N(byowner)>(); auto iter = playerItems.lower_bound(account); while (iter != playerItems.end()) { print("Item ", iter->name); iter++; }}Let’s break out the following line and delve a little deeper into what it’s responsible for;auto playerItems = items.get_index<N(byowner)>();This line is using the get_index function of our item_table instance to fetch the index we defined previously..Notice we’re using the same name N(byowner) we specified earlier to reference the index we’re seeking.And that’s secondary indexes, now we have our index, we can perform all the functions we would normally do with the primary_index..In the example we’re using lower_bound, but you could use find, get, upper_bound, begin, or end to suit your particular use case.. More details

Leave a Reply