EOSIO能夠根據高達16種索引對表進行排序。本文將會給addressbook 合約添加另壹個索引,這樣我們就可以用不壹樣的辦法對記錄進行遍歷。
Step 1: 從表中移除現有的數據
我們在之前說過,壹個表結構在它包含有數據的時候是不能對它進行修改的。允許移除數據的第壹步已經添加了。
下面我們移除在之前的教程中添加的alice和bob的所有記錄。
cleos push action addressbook erase ‘[“alice”]’ -p alice@active
cleos push action addressbook erase ‘[“bob”]’ -p bob@active
Step 2: 添加新的索引成員和getter方法
添加壹個新的成員變量以及它的getter方法到addressbook.cpp合約。由於二級索引是數字類型的,所以添加了年齡變量是uint64_t 類型的。
uint64_t age; uint64_t get_secondary_1() const { return age;}
Step 3: 添加二級索引到‘地址’表配置
把壹個字段定義為二級索引,然後address_index表需要重新配置。
typedef eosio::multi_index<”people”_n, person, indexed_by<”byage”_n, const_mem_fun<person, uint64_t, &person::get_secondary_1>> > address_index;
第三個參數,我們傳遞了indexed_by結構,它用來初始化壹個索引。
在indexed_by結構中,我們指定索引的名稱為“byage”,第二個類型參數,我們傳遞壹個函數調用操作器,它能把壹個常量提取為索引key。在本例中,我們把它指向我們之前創建的getter方法,這樣這個多索引表將按照age變量對記錄進行排序。
indexed_by<”byage”_n, const_mem_fun<person, uint64_t, &person::get_secondary_1>>
Step 4: 修改代碼
完成了上面所有步驟只後,我們現在可以更新upsert函數了。把函數的參數列表改成下面這樣:
void upsert(name user, std::string first_name, std::string last_name, uint64_t age, std::string street, std::string city, std::string state)
升級upsert函數中的age字段,像下面這樣:
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; }); } }
Step 5: 編譯與部署
編譯
eosio-cpp --abigen addressbook.cpp -o addressbook.wasm
部署
cleos set contract addressbook CONTRACTS_DIR/addressbook
Step 6: 測試
插入記錄
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
根據age索引查看alice的地址。 這裏的 — index 2參數是用來表明這個查詢是應用於二級索引的(索引#2)
cleos get table addressbook addressbook people --upper 10 \ --key-type i64 \ --index 2
妳應該會看到類似下面的內容。
{ "rows": [{ "key": "alice", "first_name": "alice", "last_name": "liddell", "age": 9, "street": "123 drink me way", "city": "wonderland", "state": "amsterdam" } ], "more": false }
查壹下bob的age
cleos get table addressbook addressbook people --upper 50 --key-type i64 --index 2
它應該會返回:
{ "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 loser", "age": 49, "street": "doesnt exist", "city": "somewhere", "state": "someplace" } ], "more": false }
整理打包
目前為止,完整的addressbook 合約:
#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; } }; typedef eosio::multi_index<"people"_n, person, indexed_by<"byage"_n, const_mem_fun<person, uint64_t, &person::get_secondary_1>>> address_index; };
Sort: Trending