Fabric链码开发——富查询
Fabric链码开发——富查询
常见的链码使用PutState和GetState就可以进行简单的增加和查找了,再不济就加入DelState。因为fabric底层都是KV数据库,所以这三个接口就可以进行增删改查的基本需求了。但是,这都是单个数据的操作如果要进行功能较为强大的数据操作,只使用这个是完全不够的。查询时一切数据操作的开始,通过官方文档,找到了这两个支持富查询的函数。(富查询只支持在CouchDB 中使用)
源代码
func (s *ChaincodeStub) GetQueryResult(query string) (StateQueryIteratorInterface, error)
func (s *ChaincodeStub) GetQueryResultWithPagination(query string, pageSize int32,bookmark string) (StateQueryIteratorInterface, *pb.QueryResponseMetadata, error)
第一个是一个简单的富查询函数,第二个是一个支持富查询的分页查询函数
// GetQueryResult documentation can be found in interfaces.go
func (s *ChaincodeStub) GetQueryResult(query string) (StateQueryIteratorInterface, error) {// Access public data by setting the collection to empty stringcollection := ""// ignore QueryResponseMetadata as it is not applicable for a rich query without paginationiterator, _, err := s.handleGetQueryResult(collection, query, nil)return iterator, err
}
// GetQueryResultWithPagination ...
func (s *ChaincodeStub) GetQueryResultWithPagination(query string, pageSize int32,bookmark string) (StateQueryIteratorInterface, *pb.QueryResponseMetadata, error) {// Access public data by setting the collection to empty stringcollection := ""metadata, err := createQueryMetadata(pageSize, bookmark)if err != nil {return nil, nil, err}return s.handleGetQueryResult(collection, query, metadata)
}
以上是他们的源码,实际上可以发现,他们都是调用handleGetQueryResult
这个函数,分页查询函数知识多了一步创建metadata,将范围打包。之后可以和GetStateByRange(startKey, endKey string)
的函数做比较。
bookmark是书签,内容是一个无序的字符数组,如果为空则会重头查询,如果不为空,则会从会从它所代表的位置开始查询,在每次分页查询的时候都可以得到一个bookmark,也就是说,下一页的查询需要带上一页的bookmark。
func (s *ChaincodeStub) handleGetQueryResult(collection, query string,metadata []byte) (StateQueryIteratorInterface, *pb.QueryResponseMetadata, error) {//获取查询结果,这一步就使用了metadata进行分页response, err := s.handler.handleGetQueryResult(collection, query, metadata, s.ChannelID, s.TxID)if err != nil {return nil, nil, err}//创建迭代器iterator := s.createStateQueryIterator(response)//进行再次封装responseMetadata, err := createQueryResponseMetadata(response.Metadata)if err != nil {return nil, nil, err}return iterator, responseMetadata, nil
}
和这两个富查询函数一起使用handleGetQueryResult
的,还有一个GetPrivateDataQueryResult
函数。这个函数看起来是查询私有数据,但私有数据是什么暂且不知道,按下不提。这四个函数都是在shim/stub.go中。
索引及数据结构
富查询目前只有couchDB支持,这是一个比较依赖数据库的功能,那就必须要有考虑一个问题:索引。参考Fabric的中文文档可以建立索引。
特别注意两点:
1.索引是依据需求来的,如果太多的索引会影响查询速率
2.索引的目录是固定的,链码同目录下的META-INF/statedb/couchdb/indexes
一个完整的索引如下:
{"index":{//要查询的字段名称,一般情况下要包含docType,对于docType的解释在后面"fields":["docType","owner"] // Names of the fields to be queried},// (可选)将创建索引的设计文件的名称。如果是一个文件包含一个索引可以不使用,官方建议也是单个索引"ddoc":"indexOwnerDoc", "name":"indexOwner","type":"json"
}
我在官方文档中还看到了一个数据结构的规范写法
type marble struct {//docType用于区分状态数据库中的各种类型的对象ObjectType string `json:"docType"` //以下的正常的数据结构Name string `json:"name"` Color string `json:"color"`Size int `json:"size"`Owner string `json:"owner"`
}
docType
用来识别这个文档的数据类型。 同时在链码数据库中也可能存在其他文档。数据库中的文档对于这些属性值来说都是可查询的。
常用函数
以下是我根据文档中给出的示例总结的富查询常用函数,主要使用getQueryResultForQueryString
和getQueryResultForQueryStringWithPagination
,后两个函数是为分页富查询函数使用的。可以写在智能合约中调用。
=========================================================================================
// getQueryResultForQueryString执行传入的查询字符串。
// 结果集被建立并作为一个字节数组返回,其中包含JSON结果。
=========================================================================================
func getQueryResultForQueryString(APIstub shim.ChaincodeStubInterface, queryString string) ([]byte, error) {fmt.Printf("- getQueryResultForQueryString queryString:\n%s\n", queryString)resultsIterator, err := APIstub.GetQueryResult(queryString)if err != nil {return nil, err}defer resultsIterator.Close()buffer, err := constructQueryResponseFromIterator(resultsIterator)if err != nil {return nil, err}fmt.Printf("- getQueryResultForQueryString queryResult:\n%s\n", buffer.String())return buffer.Bytes(), nil
}=========================================================================================
// getQueryResultForQueryStringWithPagination执行传入的查询字符串,其中包括
// 分页信息。结果集被建立并作为一个字节数组返回,其中包含JSON结果。
=========================================================================================
func getQueryResultForQueryStringWithPagination(APIstub shim.ChaincodeStubInterface, queryString string, pageSize int32, bookmark string) ([]byte, error) {fmt.Printf("- getQueryResultForQueryStringWithPagination queryString:\n%s\n", queryString)resultsIterator, responseMetadata, err := APIstub.GetQueryResultWithPagination(queryString, pageSize, bookmark)if err != nil {return nil, err}defer resultsIterator.Close()buffer, err := constructQueryResponseFromIterator(resultsIterator)if err != nil {return nil, err}bufferWithPaginationInfo := addPaginationMetadataToQueryResults(buffer, responseMetadata)fmt.Printf("- getQueryResultForQueryStringWithPagination queryResult:\n%s\n", bufferWithPaginationInfo.String())return buffer.Bytes(), nil
}
=========================================================================================
// constructQueryResponseFromIterator构建一个JSON数组,其中包含来自给定结果迭代器的查询结果。
// 一个给定的结果迭代器=========================================================================================
func constructQueryResponseFromIterator(resultsIterator shim.StateQueryIteratorInterface) (*bytes.Buffer, error) {// buffer is a JSON array containing QueryResultsvar buffer bytes.Bufferbuffer.WriteString("[")bArrayMemberAlreadyWritten := falsefor resultsIterator.HasNext() {queryResponse, err := resultsIterator.Next()if err != nil {return nil, err}// Add a comma before array members, suppress it for the first array memberif bArrayMemberAlreadyWritten == true {buffer.WriteString(",")}buffer.WriteString("{\"Key\":")buffer.WriteString("\"")buffer.WriteString(queryResponse.Key)buffer.WriteString("\"")buffer.WriteString(", \"Record\":")// Record is a JSON object, so we write as-isbuffer.WriteString(string(queryResponse.Value))buffer.WriteString("}")bArrayMemberAlreadyWritten = true}buffer.WriteString("]")return &buffer, nil
}=========================================================================================
// addPaginationMetadataToQueryResults 将包含分页的QueryResponseMetadata
// 的信息,添加到构建的查询结果中。
=========================================================================================
func addPaginationMetadataToQueryResults(buffer *bytes.Buffer, responseMetadata *pb.QueryResponseMetadata) *bytes.Buffer {buffer.WriteString("[{\"ResponseMetadata\":{\"RecordsCount\":")buffer.WriteString("\"")buffer.WriteString(fmt.Sprintf("%v", responseMetadata.FetchedRecordsCount))buffer.WriteString("\"")buffer.WriteString(", \"Bookmark\":")buffer.WriteString("\"")buffer.WriteString(responseMetadata.Bookmark)buffer.WriteString("\"}}]")return buffer
}
下面是我写的一个调用分页函数的合约函数(我把可以在SDK中调用的智能合约函数叫做合约函数)示例
func (s *SmartContract) queryCourseWithPagination(APIstub shim.ChaincodeStubInterface, args []string) pb.Response {fmt.Println("func queryCourseWithPagination start")fmt.Printf("args:%v\n", args)if len(args) != 3 {return shim.Error("arguments num not enough," + strconv.Itoa(len(args)))}queryString := args[0]//return type of ParseInt is int64pageSize, err := strconv.ParseInt(args[1], 10, 32)if err != nil {return shim.Error(err.Error())}bookmark := args[2]//之前是获取参数,在这一步调用分页富查询函数,查询出结果后转为字节流返回queryResults, err := getQueryResultForQueryStringWithPagination(APIstub, queryString, int32(pageSize), bookmark)if err != nil {return shim.Error(err.Error())}return shim.Success(queryResults)
}
chaincode常用包shim链接
Fabric链码开发——富查询相关推荐
- HyperLedger Fabric链码开发及测试
HyperLedger Fabric链码开发及测试 1.链码开发 先设计一个简单的应用场景,假设有这样的业务需求: 可以添加学校,信息包括学校名称.学校ID: 添加该学校的学生,信息包括姓名,用户ID ...
- HyperLeger Fabric开发(七)——HyperLeger Fabric链码开发
HyperLeger Fabric开发(七)--HyperLeger Fabric链码开发 一.链码开发模式 1.链码开发模式简介 Fabric的链码开发调试比较繁琐.在不使用链码开发模式的情况下,链 ...
- fabric 启动peer_编写 Fabric 链码的一般准则
我相信智能合约(链码)是 Hyperledger Fabric 区块链网络的核心.正确开发链码可以真正发挥一个安全区块链的优势,反之则会带来灾难性的后果.在这篇文章里我不打算探讨 Hyperledge ...
- 十一、区块链学习-Hyperledger Fabric (基于release-1.0) 链码开发-marbles管理
链码开发-marbles管理 1. 概述 2. marble弹珠管理 2.1实现功能 2.2chaincode链码 2.3编写测试类 2.4 跑测试类 3 搭建本地测试环境 并测试链码 3.1 挂载链 ...
- hyperledger fabric 实战开发——水产品溯源交易平台(二)
文章目录 前言 一.技术学习 1.Hyperledger fabric 1.1 流程 1.2 配置 1.3 范例解析并自写 1.3 算法实现 二.Web编写 前言 hyperledger fabric ...
- Fabric 链码Chaincode 的安装、初始化、调用、升级
Fabric 链码Chaincode 的安装.初始化.调用.升级 Fabric chaincode 上一篇文章,我们启动了一个Fabric网络,这篇文章来看看在Fabric网络进行应用的开发. 上一篇 ...
- Fabric链码常用API文档
Fabric链码API文档 一.Fabric-shim.ChaincodeInterface ChaincodeInterface 在链码当中我们必须实现ChaincodeInterface接口中定义 ...
- 智能合约链码开发和部署
智能合约链码开发和部署 文章目录 智能合约链码开发和部署 一.环境和语言 二.便签版合约实现 2.1.定义链码对象 2.2.便签对象实现 2.3.Init接口的实现 2.4.invoke接口实现和便签 ...
- Hyperledger Fabric 链码(3) 生命周期和API
1. Chaincode的5个生命周期命令 链码打包 链码安装 eg.peer chaincode install ccpack.out 链码实例化 eg. peer.sh chaincode ins ...
最新文章
- 参数定义sql 递归查询子目录
- ubuntu软件的卸载和安装
- F - Heron and His Triangle UVALive - 8206
- 提高.NET编程水平的50个要点(转载)
- tomcat session失效时间
- 在你迷茫时不如学好一门语言(送给大一的学弟学妹)
- 交易撮合引擎原理与实现【含源码】
- 蓝桥杯真题:平方和(2019 年省赛)
- 用C语言调用.bat批处理命令
- null object java_java1.8--Null Object模式
- 如何录制网络视频,屏幕录制软件哪个好
- 如何打开计算机用户账户控制面板,控制面板无法打开用户帐户
- marked扩展语法(增加自定义表情)
- python数独解题器_Python编写的超帅数独可视化解题器
- metamask连接不上本地私有节点,报错“无法获取链 IC,您的 RPC URL 地址是正确的么”
- 安卓下快速搜索文件实现历程{NDK}
- VS2017实用调试技巧
- 真王服务器文件,《真王》全国争霸赛开赛 3V3跨服登场
- 【解的封闭形式】Abel-Ruffini theorem(阿贝尔-鲁菲尼定理)
- mac系统常用操作指南