Preconditions
- It is assumed you already have a multi index table instance defined along with its mandatory primary index, otherwise take a look at the section How to instantiate a multi index table.
The steps below show how to add a secondary index to the existing multi index table.
- Add a second field,
secondary
, to the data structure that defines the row of the table, in your casetest_table
struct [[eosio::table]] test_table {
// this field stores a name for each row of the multi index table
name test_primary;
+ name secondary;
// additional data stored in table row
uint64_t datum;
// mandatory definition for primary key getter
uint64_t primary_key( ) const { return test_primary.value; }
};
- Add
by_secondary( )
method, which is the index accessor method to the new field value added. The secondary index, that will be added in step 3, will index this new data structure field.
struct [[eosio::table]] test_table {
// this field stores a name for each row of the multi index table
name test_primary;
name secondary;
// additional data stored in table row
uint64_t datum;
// mandatory definition for primary key getter
uint64_t primary_key( ) const { return test_primary.value; }
+ uint64_t by_secondary( ) const { return secondary.value; }
};
- In the
test_table
alias definition (typedef), add the definition of the secondary index by making use of theeosio::indexed_by
template.eosio::index_by
needs two parameters: the name of the index,"secid"_n
, and a function call operator which extracts the value from the secondary data member as an index key. The function call operator is achieved by employing theeosio::const_mem_fun
template which receives two parameters: the data structuretest_table
and the reference to the getter function memberby_secondary
.
- typedef eosio::multi_index<"testtaba"_n, test_table> test_tables;
+ typedef eosio::multi_index<"testtaba"_n, test_table, eosio::indexed_by<"secid"_n, eosio::const_mem_fun<test_table, uint64_t, &test_table::by_secondary>>> test_tables;
The full contract definition code with all the changes described above could look like this:
multi_index_example.hpp
#include <eosio/eosio.hpp>
using namespace eosio;
// multi index example contract class
class [[eosio::contract]] multi_index_example : public contract {
public:
using contract::contract;
// contract class constructor
multi_index_example( name receiver, name code, datastream<const char*> ds ) :
// contract base class contructor
contract(receiver, code, ds),
// instantiate multi index instance as data member (find it defined below)
testtab(receiver, receiver.value)
{ }
struct [[eosio::table]] test_table {
// this field stores a name for each row of the multi index table
name test_primary;
name secondary;
// additional data stored in table row
uint64_t datum;
// mandatory definition for primary key getter
uint64_t primary_key( ) const { return test_primary.value; }
uint64_t by_secondary( ) const { return secondary.value; }
};
// the multi index type definition, for ease of use a type alias `test_tables` is defined,
// based on the multi_index template type, parametarized with a random name, the
// test_table data structure, and the secondary index
typedef eosio::multi_index<"testtaba"_n, test_table, eosio::indexed_by<"secid"_n, eosio::const_mem_fun<test_table, uint64_t, &test_table::by_secondary>>> test_tables;
// the multi index table instance declared as a data member of type test_tables
test_tables testtab;
[[eosio::action]] void set( name user );
[[eosio::action]] void print( name user );
using set_action = action_wrapper<"set"_n, &multi_index_example::set>;
using print_action = action_wrapper<"print"_n, &multi_index_example::print>;
};