本文我们继续上一篇文章中提到的 EOS nodejs 合约交互 ( 一 ) ,这一章节,我们主要来学习 eosjs 中的 getTableRows
函数
eosjs.getTableRow() 函数
首先,我们使用下面的命令来看一下 eosjs.getTableRows()
函数的介绍
console.log(eos.getTableRows())
输出结果如下
USAGE getTableRows - Fetch smart contract data from an account. PARAMETERS { "json": { "type": "bool", "default": false }, "code": "name", "scope": "string", "table": "name", "table_key": "string", "lower_bound": { "type": "string", "default": "0" }, "upper_bound": { "type": "string", "default": "-1" }, "limit": { "type": "uint32", "default": "10" }, "key_type": { "type": "string", "doc": "The key type of --index, primary only supports (i64), all others support (i64, i128, i256, float64, float128). Special type 'name' indicates an account name." }, "index_position": { "type": "string", "doc": "1 - primary (first), 2 - secondary index (in order defined by multi_index), 3 - third index, etc" } } RETURNS { "rows": { "type": "vector", "doc": "One row per item, either encoded as hex String or JSON object" }, "more": { "type": "bool", "doc": "True if last element in data is not the end and sizeof data() < limit" } } ERRORS nothing special
看不懂这些参数和返回值的意思? 没关系,我们待会会介绍
其实,这些参数和返回结果是和 cleos get table
命令一一对应的
我们来看看 cleos get table
的帮助信息
cleos get table -h ERROR: RequiredError: account Retrieve the contents of a database table Usage: cleos get table [OPTIONS] account scope table Positionals: account TEXT The account who owns the table (required) scope TEXT The scope within the contract in which the table is found (required) table TEXT The name of the table as specified by the contract abi (required) Options: -b,--binary UINT Return the value as BINARY rather than using abi to interpret as JSON -l,--limit UINT The maximum number of rows to return -k,--key TEXT Deprecated -L,--lower TEXT JSON representation of lower bound value of key, defaults to first -U,--upper TEXT JSON representation of upper bound value of key, defaults to last --index TEXT Index number, 1 - primary (first), 2 - secondary index (in order defined by multi_index), 3 - third index, etc. Number or name of index can be specified, e.g. 'secondary' or '2'. --key-type TEXT The key type of --index, primary only supports (i64), all others support (i64, i128, i256, float64, float128, ripemd160, sha256). Special type 'name' indicates an account name. --encode-type TEXT The encoding type of key_type (i64 , i128 , float64, float128) only support decimal encoding e.g. 'dec'i256 - supports both 'dec' and 'hex', ripemd160 and sha256 is 'hex' only
参数说明
eos.getTableRows | cleos get table | 类型 | 默认值 | 说明 |
---|---|---|---|---|
json | - | bool | false | 设置返回格式是否为 json,如果为 false 则显示原始数据 |
code | account | text | 必填 | 合约所在的账号 |
scope | scope | text | 必填 | 数据的拥有者,一般和 code/account 一样 |
table | table | text | 必填 | 表名 |
table_key | -k,--key | text | - | 要查找的索引名称,已废弃 |
lower_bound | -L,--lower | text | "0" | 要查找的索引的最小值,默认为第一条数据,包含这个最小值 |
upper_bound | -U,--upper | text | "-1" | 要查找的索引的最大值,默认为最后一条数据之后,不包含这个最大值 |
limit | -l,--limit | uint | 10 | 返回的数据量,默认为 10 |
key_type | --key-type | string | "i64" | 索引的数据类型,主键默认为 "i64",支持的其它类型有:i64, i128, i256, float64, float128,name |
index_position | --index | TEXT | "1" | 索引的位置,主索引为 1, 第二索引为 2 ,以此类推 |
需要注意的是
-
lower_bound
参数返回的结果是包含该值的,也就是>=
的关系 -
upper_bound
参数返回的结果是不包含该值的,也就是<
的关系 -
key_type
参数可以设置为name
值,也就是可以传递账号名比如,我们的某个索引用到了
name from
作为索引,在合约中的代码如下uint64_t get_from() const { return from.value;}
那么,在 eosjs 中,则可以如下传递
{ "key_type":"name", "lower_bound:"xiaoming" }
-
index_position
参数是索引所在的位置,主键索引默认为 1假设我们的合约中这样的一个表
struct record { uint64_t primary; uint64_t secondary_1; uint128_t secondary_2; uint256_t secondary_3; double secondary_4; long double secondary_5; uint64_t primary_key() const { return primary; } uint64_t get_secondary_1() const { return secondary_1; } uint128_t get_secondary_2() const { return secondary_2; } uint256_t get_secondary_3() const { return secondary_3; } double get_secondary_4() const { return secondary_4; } long double get_secondary_5() const { return secondary_5; } }; typedef multi_index<name("records"), record, indexed_by< name("bysecondary1"), const_mem_fun<record, uint64_t, &record::get_secondary_1> >, indexed_by< name("bysecondary2"), const_mem_fun<record, uint128_t, &record::get_secondary_2> >, indexed_by< name("bysecondary3"), const_mem_fun<record, uint256_t, &record::get_secondary_3> >, indexed_by< name("bysecondary4"), const_mem_fun<record, double, &record::get_secondary_4> >, indexed_by< name("bysecondary5"), const_mem_fun<record, long double, &record::get_secondary_5> > > records;
那么,传递
index_position
参数时,各个索引的值为索引 index_position 值 primary_key 1 bysecondary1 2 bysecondary2 3 bysecondary3 4 ... ...
返回值说明
如果表存在,且没有发生任何错误,那么会返回一个正常的结果
返回的结果有两个参数
eos.getTableRows | 类型 | 默认值 | 说明 |
---|---|---|---|
rows | array | [] | 保存返回结果的数组 |
more | bool | false | 是否有更多数据 |
触发的异常
如果表不存在,或者某些参数错误,则会抛出一个异常
比如,使用下面的命令获取一个不存在的表时,会抛出表不存在的错误
cleos get table micromsg micromsg status Error 3060003: Contract Table Query Exception Most likely, the given table doesn't exist in the blockchain.
如果使用 eosjs
,则需要使用 catch
方法来捕获这个异常
eos.getTableRows({ "code": config.account.contract, "scope": config.account.contract, "table": "status" }).then( rs => console.log("ok:",rs)).catch(e => console.log(e))
运行结果如下
node micromsg.js { Error: {"code":500,"message":"Internal Service Error","error":{"code":3060003,"name":"contract_table_query_exception","what":"Contract Table Query Exception","details":[]}} at /Users/yufei/Downloads/contract/micromsg/node_modules/eosjs-api/lib/apigen.js:112:23 at process.internalTickCallback (internal/process/next_tick.js:77:7) status: 500, statusText: 'Internal Server Error' }
范例
-
使用默认参数获取合约
micromsg
下的表messages
的数据eos.getTableRows({ "code": config.account.contract, "scope": config.account.contract, "table": "messages" }).then( rs => console.log(rs)).catch(e => console.log(e))
输出结果如下
{ rows: [ '00000000000000000000006c3a498deb0000006cd2468deb0a69206d69737320796f751425035c0000000000', '01000000000000000000006c3a498deb0000006cd2468deb0a69206d69737320796f755f25035c0000000001', '02000000000000000000006c3a498deb0000006cd2468deb0a69206d69737320796f756025035c0000000000', '03000000000000000000006c3a498deb0000006cd2468deb0a69206d69737320796f756025035c0000000000', '04000000000000000000006c3a498deb0000006cd2468deb0a69206d69737320796f756125035c0000000000', '05000000000000000000006c3a498deb0000006cd2468deb0a69206d69737320796f756125035c0000000000' ], more: false }
-
默认的结果显示的是 16 进制,我们可以使用
json:true
来显示 json 格式eos.getTableRows({ "code": config.account.contract, "scope": config.account.contract, "table": "messages", "json":true }).then( rs => console.log(rs)).catch(e => console.log(e))
运行结果如下
{ rows: [ { id: 0, from: 'xiaoming', to: 'xiaohong', msg: 'i miss you', tm: 1543709972, readed: 0 }, { id: 1, from: 'xiaoming', to: 'xiaohong', msg: 'i miss you', tm: 1543710047, readed: 1 }, { id: 2, from: 'xiaoming', to: 'xiaohong', msg: 'i miss you', tm: 1543710048, readed: 0 }, { id: 3, from: 'xiaoming', to: 'xiaohong', msg: 'i miss you', tm: 1543710048, readed: 0 }, { id: 4, from: 'xiaoming', to: 'xiaohong', msg: 'i miss you', tm: 1543710049, readed: 0 }, { id: 5, from: 'xiaoming', to: 'xiaohong', msg: 'i miss you', tm: 1543710049, readed: 0 } ], more: false }
-
如果我们只想显示有限的几条,比如 1 条,那么可以使用
limit:1
参数eos.getTableRows({ "code": config.account.contract, "scope": config.account.contract, "table": "messages", "json":true, "limit":1 }).then( rs => console.log(rs)).catch(e => console.log(e))
运行结果如下
{ rows: [ { id: 0, from: 'xiaoming', to: 'xiaohong', msg: 'i miss you', tm: 1543709972, readed: 0 } ], more: true }
在限制 1 条数据的情况下, more
参数为 true
就代表有更多数据。
但,你会发现,这个 more
有点鸡肋,因为,并没有参数来设置偏移量。
那么要获取更多数据要怎么做呢? 以后我会单独拿一章节来讲述
-
如果想根据条件大于等于来获取,我们可以使用
lower_bound
参数,比如我们想获取id
大于等于 4 的所有数据,可以设置参数lower_bound:4
因为 id 是主索引,而主索引是默认索引,不需要设置
index_position
等eos.getTableRows({ "code": config.account.contract, "scope": config.account.contract, "table": "messages", "json":true, "lower_bound":4 }).then( rs => console.log(rs)).catch(e => console.log(e))
运行结果如下
{ rows: [ { id: 4, from: 'xiaoming', to: 'xiaohong', msg: 'i miss you', tm: 1543710049, readed: 0 }, { id: 5, from: 'xiaoming', to: 'xiaohong', msg: 'i miss you', tm: 1543710049, readed: 0 } ], more: false }
-
如果想根据条件小于来获取,可以使用
upper_bound
参数,比如要获取 id 小于 3 的记录,可以设置参数upper_bound:3
eos.getTableRows({ "code": config.account.contract, "scope": config.account.contract, "table": "messages", "json":true, "upper_bound":3 }).then( rs => console.log(rs)).catch(e => console.log(e))
运行结果如下
{ rows: [ { id: 0, from: 'xiaoming', to: 'xiaohong', msg: 'i miss you', tm: 1543709972, readed: 0 }, { id: 1, from: 'xiaoming', to: 'xiaohong', msg: 'i miss you', tm: 1543710047, readed: 1 }, { id: 2, from: 'xiaoming', to: 'xiaohong', msg: 'i miss you', tm: 1543710048, readed: 0 } ], more: false }
从运行结果中可以看出,
upper_bound
的结果并不包含upper_bound
参数本身 -
lower_bound
和upper_bound
参数可以一起使用,比如要获取 id 大于等于 2 且 id 小于 4 的记录,可以同时设置lower_bound:2
和upper_bound:4
参数eos.getTableRows({ "code": config.account.contract, "scope": config.account.contract, "table": "messages", "json":true, "lower_bound":2, "upper_bound":4 }).then( rs => console.log(rs)).catch(e => console.log(e))
运行结果如下
{ rows: [ { id: 2, from: 'xiaoming', to: 'xiaohong', msg: 'i miss you', tm: 1543710048, readed: 0 }, { id: 3, from: 'xiaoming', to: 'xiaohong', msg: 'i miss you', tm: 1543710048, readed: 0 } ], more: false }
-
如果要查找的数据不是主索引则必须使用
index_position
参数因为我们并没有创建第二索引,所以我们只能使用主索引来模拟,比如我们要在
id
这个索引上使用lower_bound
查找 id 大于等于 5 的记录,可以如下使用eos.getTableRows({ "code": config.account.contract, "scope": config.account.contract, "table": "messages", "json":true, "index_position":1, "lower_bound":5, }).then( rs => console.log(rs)).catch(e => console.log(e))
输出结果如下
{ rows: [ { id: 5, from: 'xiaoming', to: 'xiaohong', msg: 'i miss you', tm: 1543710049, readed: 0 } ], more: false }
-
如果使用的索引的类型不是
i64
,则不许使用key_type
指定索引的类型因为我们并没有创建第二索引,所以我们只能使用主索引来模拟,比如我们要在
id
这个索引上使用lower_bound
查找 id 大于等于 5 的记录,可以如下使用eos.getTableRows({ "code": config.account.contract, "scope": config.account.contract, "table": "messages", "json":true, "key_type":"i64", "index_position":1, "lower_bound":5, }).then( rs => console.log(rs)).catch(e => console.log(e))
输出结果如下
{ rows: [ { id: 5, from: 'xiaoming', to: 'xiaohong', msg: 'i miss you', tm: 1543710049, readed: 0 } ], more: false }
后记
其实,eosjs.getTableRows()
的使用还是比较简单的。
但在实际的运用中的很复杂,因为缺少 offset
参数,当要获取偏移量的时候,就不得不做一些取巧的动作
范例源码
const Eos = require('eosjs'); const config = { account: { contract: "micromsg", // 合约账号 from: "xiaoming", // 发送者账号 to: "xiaohong" // 接收者账号 }, network: { protocol:'http', // 协议 http or https host: 'localhost', // 远程主机 port: '8080', // 远程端口号 keyProvider:['5J6Ly95q876iEwG1c4bBcWAWqHbibRmhDsxtSrnsSswpT7r7gAC'], // 私钥 chainId: 'cf057bbfb72640471fd910bcb67639c22df9f92470936cddc1ade0e2f2e7dc4f', // EOS 链 id timeout: 10000 // 10s 超时 } } var eos = Eos(config.network); // 获取帮助信息 console.log(eos.getTableRows()); // 表不存在 eos.getTableRows({ "code": config.account.contract, "scope": config.account.contract, "table": "status" }).then( rs => console.log("ok:",rs)).catch(e => console.log(e)) eos.getTableRows({ "code": config.account.contract, "scope": config.account.contract, "table": "messages" }).then( rs => console.log(rs)).catch(e => console.log(e)) eos.getTableRows({ "code": config.account.contract, "scope": config.account.contract, "table": "messages", "json":true }).then( rs => console.log(rs)).catch(e => console.log(e)) eos.getTableRows({ "code": config.account.contract, "scope": config.account.contract, "table": "messages", "json":true, "limit":1 }).then( rs => console.log(rs)).catch(e => console.log(e)) eos.getTableRows({ "code": config.account.contract, "scope": config.account.contract, "table": "messages", "json":true, "lower_bound":4 }).then( rs => console.log(rs)).catch(e => console.log(e)) eos.getTableRows({ "code": config.account.contract, "scope": config.account.contract, "table": "messages", "json":true, "upper_bound":3 }).then( rs => console.log(rs)).catch(e => console.log(e)) eos.getTableRows({ "code": config.account.contract, "scope": config.account.contract, "table": "messages", "json":true, "lower_bound":2, "upper_bound":4 }).then( rs => console.log(rs)).catch(e => console.log(e)) eos.getTableRows({ "code": config.account.contract, "scope": config.account.contract, "table": "messages", "json":true, "index_position":1, "lower_bound":5, }).then( rs => console.log(rs)).catch(e => console.log(e)) eos.getTableRows({ "code": config.account.contract, "scope": config.account.contract, "table": "messages", "json":true, "key_type":"i64", "index_position":1, "lower_bound":5, }).then( rs => console.log(rs)).catch(e => console.log(e))