当CouchDB查询返回大型结果集时,可以使用一系列API,这些API可以通过调用链代码来对结果列表进行分页。 分页提供了一种机制,通过指定页面大小和起始点来划分结果集——一个指示结果集开始位置的书签。 客户端应用程序迭代地调用执行查询的链代码,直到不再返回结果。
我们将使用Marbles示例函数queryMarblesWithPagination来演示如何在链代码和客户端应用程序中实现分页。
https://github.com/hyperledger/fabric-samples/blob/master/chaincode/marbles02/go/marbles_chaincode.go
queryMarblesWithPagination –具有分页的临时丰富查询的示例。 这是一个查询,其中(选择器)字符串可以传递到类似于上面示例的函数中。 在这种情况下,查询还包括pageSize以及书签。
为了展示分页,需要更多数据。 此示例假定您已从上方添加了marble1。 在对等容器中运行以下命令以创建“tom”拥有的四个大理石,以创建由“tom”拥有的总共五个大理石:
peer chaincode invoke -o orderer.example.com:7050 --tls --cafile /opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/ordererOrganizations/example.com/orderers/orderer.example.com/msp/tlscacerts/tlsca.example.com-cert.pem -C $CHANNEL_NAME -n marbles -c '{"Args":["initMarble","marble2","yellow","35","tom"]}'
peer chaincode invoke -o orderer.example.com:7050 --tls --cafile /opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/ordererOrganizations/example.com/orderers/orderer.example.com/msp/tlscacerts/tlsca.example.com-cert.pem -C $CHANNEL_NAME -n marbles -c '{"Args":["initMarble","marble3","green","20","tom"]}'
peer chaincode invoke -o orderer.example.com:7050 --tls --cafile /opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/ordererOrganizations/example.com/orderers/orderer.example.com/msp/tlscacerts/tlsca.example.com-cert.pem -C $CHANNEL_NAME -n marbles -c '{"Args":["initMarble","marble4","purple","20","tom"]}'
peer chaincode invoke -o orderer.example.com:7050 --tls --cafile /opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/ordererOrganizations/example.com/orderers/orderer.example.com/msp/tlscacerts/tlsca.example.com-cert.pem -C $CHANNEL_NAME -n marbles -c '{"Args":["initMarble","marble5","blue","40","tom"]}'
除了前一个示例中的查询参数之外,queryMarblesWithPagination还添加了pagesize和bookmark。 PageSize指定每个查询返回的记录数。 书签是一个“锚”告诉couchDB从哪里开始页面。 (每个结果页面都会返回一个唯一的书签。)
queryMarblesWithPagination是Marbles链码中函数的名称。 注意垫片shim.ChaincodeStubInterface用于访问和修改分类帐。 getQueryResultForQueryStringWithPagination()将queryString以及pagesize和bookmark传递给shim API GetQueryResultWithPagination()。
func (t *SimpleChaincode) queryMarblesWithPagination(stub shim.ChaincodeStubInterface, args []string) pb.Response {
// 0
// "queryString"
if len(args) < 3 {
return shim.Error("Incorrect number of arguments. Expecting 3")
}
queryString := args[0]
//return type of ParseInt is int64
pageSize, err := strconv.ParseInt(args[1], 10, 32)
if err != nil {
return shim.Error(err.Error())
}
bookmark := args[2]
queryResults, err := getQueryResultForQueryStringWithPagination(stub, queryString, int32(pageSize), bookmark)
if err != nil {
return shim.Error(err.Error())
}
return shim.Success(queryResults)
}
以下示例是一个peer命令,它调用queryMarblesWithPagination,pageSize为3且未指定书签。
注意⚠️:如果未指定书签,则查询以“第一”记录页开头。
```
// Rich Query with index name explicitly specified and a page size of 3:
peer chaincode query -C $CHANNEL_NAME -n marbles -c '{"Args":["queryMarblesWithPagination", "{\"selector\":{\"docType\":\"marble\",\"owner\":\"tom\"}, \"use_index\":[\"_design/indexOwnerDoc\", \"indexOwner\"]}","3",""]}'
```
收到以下响应(为清晰起见添加了回车),因为pagsize设置为3,所以返回五个大理石中的三个:
```
[{"Key":"marble1", "Record":{"color":"blue","docType":"marble","name":"marble1","owner":"tom","size":35}},
{"Key":"marble2", "Record":{"color":"yellow","docType":"marble","name":"marble2","owner":"tom","size":35}},
{"Key":"marble3", "Record":{"color":"green","docType":"marble","name":"marble3","owner":"tom","size":20}}]
[{"ResponseMetadata":{"RecordsCount":"3",
"Bookmark":"g1AAAABLeJzLYWBgYMpgSmHgKy5JLCrJTq2MT8lPzkzJBYqz5yYWJeWkGoOkOWDSOSANIFk2iCyIyVySn5uVBQAGEhRz"}}]
⚠️:书签由CouchDB为每个查询唯一生成,并表示结果集中的占位符。 在后续的查询迭代中传递返回的书签以检索下一组结果。
以下是使用pageSize为3调用queryMarblesWithPagination的peer命令。请注意,这次查询包含从上一个查询返回的书签。
peer chaincode query -C $CHANNEL_NAME -n marbles -c '{"Args":["queryMarblesWithPagination", "{\"selector\":{\"docType\":\"marble\",\"owner\":\"tom\"}, \"use_index\":[\"_design/indexOwnerDoc\", \"indexOwner\"]}","3","g1AAAABLeJzLYWBgYMpgSmHgKy5JLCrJTq2MT8lPzkzJBYqz5yYWJeWkGoOkOWDSOSANIFk2iCyIyVySn5uVBQAGEhRz"]}'
收到以下响应(为清楚起见,添加了回车)。 检索最后两条记录:
[{"Key":"marble4", "Record":{"color":"purple","docType":"marble","name":"marble4","owner":"tom","size":20}},
{"Key":"marble5", "Record":{"color":"blue","docType":"marble","name":"marble5","owner":"tom","size":40}}]
[{"ResponseMetadata":{"RecordsCount":"2",
"Bookmark":"g1AAAABLeJzLYWBgYMpgSmHgKy5JLCrJTq2MT8lPzkzJBYqz5yYWJeWkmoKkOWDSOSANIFk2iCyIyVySn5uVBQAGYhR1"}}]
最后一个命令是一个peer命令,用于调用queryMarblesWithPagination,其pageSize为3,并带有上一个查询的书签。
peer chaincode query -C $CHANNEL_NAME -n marbles -c '{"Args":["queryMarblesWithPagination", "{\"selector\":{\"docType\":\"marble\",\"owner\":\"tom\"}, \"use_index\":[\"_design/indexOwnerDoc\", \"indexOwner\"]}","3","g1AAAABLeJzLYWBgYMpgSmHgKy5JLCrJTq2MT8lPzkzJBYqz5yYWJeWkmoKkOWDSOSANIFk2iCyIyVySn5uVBQAGYhR1"]}'
收到以下响应(为清楚起见,添加了回车)。 没有返回任何记录,表明已检索到所有页面:
[]
[{"ResponseMetadata":{"RecordsCount":"0",
"Bookmark":"g1AAAABLeJzLYWBgYMpgSmHgKy5JLCrJTq2MT8lPzkzJBYqz5yYWJeWkmoKkOWDSOSANIFk2iCyIyVySn5uVBQAGYhR1"}}]
有关客户端应用程序如何使用分页迭代结果集的示例,请在Marbles示例中搜索getQueryResultForQueryStringWithPagination函数。
https://github.com/hyperledger/fabric-samples/blob/master/chaincode/marbles02/go/marbles_chaincode.go