EOS nodejs 合约交互 ( 二 ) - getTableRows 获取表数据

yufei       5 年, 4 月 前       3400

本文我们继续上一篇文章中提到的 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 ,以此类推

需要注意的是

  1. lower_bound 参数返回的结果是包含该值的,也就是 >= 的关系

  2. upper_bound 参数返回的结果是不包含该值的,也就是 < 的关系

  3. key_type 参数可以设置为 name 值,也就是可以传递账号名

    比如,我们的某个索引用到了 name from 作为索引,在合约中的代码如下

    uint64_t get_from() const { return from.value;}
    

    那么,在 eosjs 中,则可以如下传递

    {
        "key_type":"name",
        "lower_bound:"xiaoming"
    }
    
  4. 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' }

范例

  1. 使用默认参数获取合约 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 }
    
  2. 默认的结果显示的是 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 }
    
  3. 如果我们只想显示有限的几条,比如 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 有点鸡肋,因为,并没有参数来设置偏移量。

那么要获取更多数据要怎么做呢? 以后我会单独拿一章节来讲述

  1. 如果想根据条件大于等于来获取,我们可以使用 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 }
    
  2. 如果想根据条件小于来获取,可以使用 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 参数本身

  3. lower_boundupper_bound 参数可以一起使用,比如要获取 id 大于等于 2 且 id 小于 4 的记录,可以同时设置 lower_bound:2upper_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 }
    
  4. 如果要查找的数据不是主索引则必须使用 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 }
    
  5. 如果使用的索引的类型不是 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))
目前尚无回复
简单教程 = 简单教程,简单编程
简单教程 是一个关于技术和学习的地方
现在注册
已注册用户请 登入
关于   |   FAQ   |   我们的愿景   |   广告投放   |  博客

  简单教程,简单编程 - IT 入门首选站

Copyright © 2013-2022 简单教程 twle.cn All Rights Reserved.