Vexanium Docs
  • Welcome!
  • Overview
    • Vexanium Toolchain
    • Core Concepts
    • Technical Features
  • Getting Started
    • Development Environment
      • Prerequisites
      • Before You Begin
      • Install VEX.CDT
      • Create Development Wallet
      • Start keosd and nodeos
      • Create Development Accounts
    • Smart Contract Development
      • Hello World Contract
      • Deploy, Issue and Transfer Tokens
      • Understanding ABI Files
      • Data Persistence
      • Secondary Indices
      • Adding Inline Actions
      • Inline Actions to External Contracts
      • Payable actions
      • Creating and Linking Custom Permissions
  • Vexanium Protocol
    • Consensus Protocol
    • Transaction Protocol
    • Network Peer Protocol
    • Accounts and Permissions
  • Vexanium DAO - Governance
    • DPOS Governance
    • Active Block Producers
  • Reference
    • API Reference
      • API V2 Migrations
    • Smart Contract
      • C++ Smart Contract
        • Hello World Contract
        • Simple Token Farming Contract
        • Employee Attendance Contract
      • Solidity ( EVM )
        • Setup Metamask
        • To Do List Contract
  • Resources
Powered by GitBook
On this page
  • Step 1: Remove existing data from table​
  • Step 2: Add new index member and getter​
  • Step 3: Add secondary index to addresses table configuration​
  • Step 4: Modify code​
  • Step 5: Compile and Deploy​
  • Step 6: Test it​
  • Wrapping Up​
  • What's Next?​
  1. Getting Started
  2. Smart Contract Development

Secondary Indices

PreviousData PersistenceNextAdding Inline Actions

Last updated 2 years ago

VEXANIUM has the ability to sort tables by up to 16 indices. In the following section, we're going to add another index to the addressbook contract, so we can iterate through the records in a different way.

Step 1: Remove existing data from table

As mentioned earlier, a table's struct cannot be modified when it contains data. This first step allows the removal of the data already added.

Remove all records of alice and bob that were added in previous tutorial.

cleos push action addressbook erase '["alice"]' -p alice@active
cleos push action addressbook erase '["bob"]' -p bob@active

Step 2: Add new index member and getter

Add a new member variable and its getter to the addressbook.cpp contract. Since the secondary index needs to be numeric field, a uint64_t age variable is added.

uint64_t age;
uint64_t get_secondary_1() const { return age;}

Step 3: Add secondary index to addresses table configuration

A field has been defined as the secondary index, next the address_index table needs to be reconfigured.

using address_index = eosio::multi_index<"people"_n, person,
indexed_by<"byage"_n, const_mem_fun<person, uint64_t, &person::get_secondary_1>>
>;

In the third parameter, we pass a indexed_by struct which is used to instantiate a index.

In that indexed_by struct, we specify the name of index as "byage" and the second type parameter as a function call operator which extracts a const value as an index key. In this case, we point it to the getter we created earlier so this multiple index table will index records by the age variable.

indexed_by<"byage"_n, const_mem_fun<person, uint64_t, &person::get_secondary_1>>

With all the changes in previous steps, we can now update the upsert function. Change the function parameter list to the following:

void upsert(name user, std::string first_name, std::string last_name, uint64_t age, std::string street, std::string city, std::string state)

Add additional lines to update age field in upsert function as the following:

void upsert(name user, std::string first_name, std::string last_name, uint64_t age, std::string street, std::string city, std::string state) {
  require_auth( user );
  address_index addresses( get_first_receiver(), get_first_receiver().value);
  auto iterator = addresses.find(user.value);
  if( iterator == addresses.end() )
  {
    addresses.emplace(user, [&]( auto& row ) {
      row.key = user;
      row.first_name = first_name;
      row.last_name = last_name;
      // -- Add code below --
      row.age = age;
      row.street = street;
      row.city = city;
      row.state = state;
    });
  }
  else {
    addresses.modify(iterator, user, [&]( auto& row ) {
      row.key = user;
      row.first_name = first_name;
      row.last_name = last_name;
      // -- Add code below --
      row.age = age;
      row.street = street;
      row.city = city;
      row.state = state;
    });
  }
}

Compile

eosio-cpp --abigen addressbook.cpp -o addressbook.wasm

Deploy

cleos set contract addressbook CONTRACTS_DIR/addressbook

Insert records

cleos push action addressbook upsert '["alice", "alice", "liddell", 9, "123 drink me way", "wonderland", "amsterdam"]' -p alice@active
cleos push action addressbook upsert '["bob", "bob", "is a guy", 49, "doesnt exist", "somewhere", "someplace"]' -p bob@active

Look up alice's address by the age index. Here the --index 2 parameter is used to indicate that the query applies to the secondary index

cleos get table addressbook addressbook people --upper 10 \
--key-type i64 \
--index 2

You should see something like the following

{
  "rows": [{
      "key": "alice",
      "first_name": "alice",
      "last_name": "liddell",
      "age": 9,
      "street": "123 drink me way",
      "city": "wonderland",
      "state": "amsterdam"
    }
  ],
  "more": false,
  "next_key": ""
}

Look it up by Bob's age

cleos get table addressbook addressbook people --upper 50 --key-type i64 --index 2

It should return

{
  "rows": [{
      "key": "alice",
      "first_name": "alice",
      "last_name": "liddell",
      "age": 9,
      "street": "123 drink me way",
      "city": "wonderland",
      "state": "amsterdam"
    },{
      "key": "bob",
      "first_name": "bob",
      "last_name": "is a guy",
      "age": 49,
      "street": "doesnt exist",
      "city": "somewhere",
      "state": "someplace"
    }
  ],
  "more": false
}

The complete addressbook contract up to this point:

#include <eosio/eosio.hpp>
#include <eosio/print.hpp>

using namespace eosio;

class [[eosio::contract("addressbook")]] addressbook : public eosio::contract {

public:

  addressbook(name receiver, name code,  datastream<const char*> ds): contract(receiver, code, ds) {}

  [[eosio::action]]
  void upsert(name user, std::string first_name, std::string last_name, uint64_t age, std::string street, std::string city, std::string state) {
    require_auth( user );
    address_index addresses(get_first_receiver(),get_first_receiver().value);
    auto iterator = addresses.find(user.value);
    if( iterator == addresses.end() )
    {
      addresses.emplace(user, [&]( auto& row ) {
       row.key = user;
       row.first_name = first_name;
       row.last_name = last_name;
       row.age = age;
       row.street = street;
       row.city = city;
       row.state = state;
      });
    }
    else {
      addresses.modify(iterator, user, [&]( auto& row ) {
        row.key = user;
        row.first_name = first_name;
        row.last_name = last_name;
        row.age = age;
        row.street = street;
        row.city = city;
        row.state = state;
      });
    }
  }

  [[eosio::action]]
  void erase(name user) {
    require_auth(user);

    address_index addresses(get_self(), get_first_receiver().value);

    auto iterator = addresses.find(user.value);
    check(iterator != addresses.end(), "Record does not exist");
    addresses.erase(iterator);
  }

private:
  struct [[eosio::table]] person {
    name key;
    std::string first_name;
    std::string last_name;
    uint64_t age;
    std::string street;
    std::string city;
    std::string state;

    uint64_t primary_key() const { return key.value; }
    uint64_t get_secondary_1() const { return age; }

  };

  using address_index = eosio::multi_index<"people"_n, person, indexed_by<"byage"_n, const_mem_fun<person, uint64_t, &person::get_secondary_1>>>;

};

Step 4: Modify code

Step 5: Compile and Deploy

Step 6: Test it

Wrapping Up

What's Next?

: Learn how to construct actions and send those actions from within a contract.

​
​
​
​
​
​
​
​
Adding Inline Actions