2.5 第二索引
优质
小牛编辑
133浏览
2023-12-01
EOSIO有能力存储最多16个索引.在这一章节,我们将会添加另一个索引到addressbook
合约中, 以让我们以另一种方式来迭代记录.
Step 1: 移除表中已经存在的数据
前面提到过, 当一个表有数据时,它的strcut不能被修改. 首先,让我们先将添加过的数据都移除掉.
移除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
表配置
我们现在将要有一个字段成为第二索引, 我们需要重新配置 address_index table.
typedef eosio::multi_index<"people"_n, person,
indexed_by<"byage"_n, const_mem_fun<person, uint64_t, &person::get_secondary_1>>
> address_index;
第三个参数,我们传入了index_by
struct, 它会被用来实例化索引.
在index_by
struct中, 我们指定了索引的名字为byage
,作为函数调用操作符的第二个类型参数应该提取一个const值作为索引键.现在,我们将先前创建好的get_secondary_1
指定给它,现在这个multiple index table会根据age
变量来索引记录了.
indexed_by<"byage"_n, const_mem_fun<person, uint64_t, &person::get_secondary_1>>
Step 4: 修改upsert函数
因为我们在multi_index_table中声明了age字段,现在需要去upsert
函数中增加该字段,以让其可以存到table中.
修改完multi_index_table和upsert函数后的addressbook.cpp
如下所示:
#include <eosiolib/eosio.hpp>
#include <eosiolib/print.hpp>
using namespace eosio;
class [[eosio::contract]] addressbook : public eosio::contract {
public:
using contract::contract;
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(_code, _code.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 {
std::string changes;
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(_self, _code.value);
auto iterator = addresses.find(user.value);
eosio_assert(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;
std::string street;
std::string city;
std::string state;
uint64_t age;
uint64_t get_secondary_1() const { return age; }
uint64_t primary_key() const { return key.value; }
};
typedef eosio::multi_index<"people"_n, person,
indexed_by<"byage"_n, const_mem_fun < person, uint64_t, &person::get_secondary_1>>
>
address_index;
};
EOSIO_DISPATCH( addressbook, (upsert)(erase)
)
Step 5: 编译与部署
编译:
eosio-cpp -o addressbook.wasm addressbook.cpp --abigen
部署:
cleos set contract addressbook /Users/zhong/coding/CLion/contracts/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
参数来指定我们将使用哪个索引,使用--upper 10
来指定查询的上限值是多少.
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的地址.我们增加了--lower 10
来指定查询索引的最小值应该为10.
cleos get table addressbook addressbook people --upper 50 --lower 10 \
--key-type i64 --index 2
你应该可以得到以下返回:
{
"rows": [{
"key": "bob",
"first_name": "bob",
"last_name": "is a guy",
"street": "doesnt exist",
"city": "somewhere",
"state": "someplace",
"age": 49
}
],
"more": false
}