@@ -13,6 +13,7 @@ The tutorial will take you through the following steps:
13
13
#. :ref: `cdb-add-index `
14
14
#. :ref: `cdb-install-instantiate `
15
15
#. :ref: `cdb-query `
16
+ #. :ref: `cdb-pagination `
16
17
#. :ref: `cdb-update-index `
17
18
#. :ref: `cdb-delete-index `
18
19
@@ -495,6 +496,155 @@ The query runs successfully and the index is leveraged with the following result
495
496
496
497
Query Result: [{" Key" :" marble1" , " Record" :{" color" :" blue" ," docType" :" marble" ," name" :" marble1" ," owner" :" tom" ," size" :35}}]
497
498
499
+ .. _cdb-pagination:
500
+
501
+
502
+ Query the CouchDB State Database With Pagination
503
+ ~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
504
+
505
+ When large result sets are returned by CouchDB queries, a set of APIs is
506
+ available which can be called by chaincode to paginate the list of results.
507
+ Pagination provides a mechanism to partition the result set by
508
+ specifying a ` ` pagesize` ` and a start point -- a ` ` bookmark` ` which indicates
509
+ where to begin the result set. The client application iteratively invokes the
510
+ chaincode that executes the query until no more results are returned. For more information refer to
511
+ this ` topic on pagination with CouchDB < http://hyperledger-fabric.readthedocs.io/en/master/couchdb_as_state_database.html#couchdb-pagination> ` __.
512
+
513
+
514
+ We will use the ` Marbles sample < https://github.com/hyperledger/fabric-samples/blob/master/chaincode/marbles02/go/marbles_chaincode.go> ` __
515
+ function ``queryMarblesWithPagination`` to demonstrate how
516
+ pagination can be implemented in chaincode and the client application.
517
+
518
+ * ** queryMarblesWithPagination** --
519
+
520
+ Example of an ** ad hoc rich query with pagination** . This is a query
521
+ where a (selector) string can be passed into the function similar to the
522
+ above example. In this case, a ` ` pageSize` ` is also included with the query as
523
+ well as a ` ` bookmark` ` .
524
+
525
+ In order to demonstrate pagination, more data is required. This example assumes
526
+ that you have already added marble1 from above. Run the following commands in
527
+ the peer container to create four more marbles owned by " tom" , to create a
528
+ total of five marbles owned by " tom" :
529
+
530
+ :guilabel:` Try it yourself`
531
+
532
+ .. code:: bash
533
+
534
+ 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"]}'
535
+ 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"]}'
536
+ 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"]}'
537
+ 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"]}'
538
+
539
+ In addition to the arguments for the query in the previous example,
540
+ queryMarblesWithPagination adds ` ` pagesize` ` and ` ` bookmark` ` . ` ` PageSize` `
541
+ specifies the number of records to return per query. The ` ` bookmark` ` is an
542
+ " anchor" telling couchDB where to begin the page. (Each page of results returns
543
+ a unique bookmark.)
544
+
545
+ * ` ` queryMarblesWithPagination` `
546
+ Name of the function in the Marbles chaincode. Notice a ` shim < https://godoc.org/github.com/hyperledger/fabric/core/chaincode/shim> ` __
547
+ ` ` shim.ChaincodeStubInterface` ` is used to access and modify the ledger. The
548
+ ``getQueryResultForQueryStringWithPagination ()` ` passes the queryString along
549
+ with the pagesize and bookmark to the shim API ``GetQueryResultWithPagination ()` ` .
550
+
551
+ .. code:: bash
552
+
553
+ func (t * SimpleChaincode) queryMarblesWithPagination(stub shim.ChaincodeStubInterface, args []string) pb.Response {
554
+
555
+ // 0
556
+ // " queryString"
557
+ if len(args) < 3 {
558
+ return shim.Error(" Incorrect number of arguments. Expecting 3" )
559
+ }
560
+
561
+ queryString := args[0]
562
+ //return type of ParseInt is int64
563
+ pageSize, err := strconv.ParseInt(args[1], 10, 32)
564
+ if err ! = nil {
565
+ return shim.Error(err.Error ())
566
+ }
567
+ bookmark := args[2]
568
+
569
+ queryResults, err := getQueryResultForQueryStringWithPagination(stub, queryString, int32(pageSize), bookmark)
570
+ if err ! = nil {
571
+ return shim.Error(err.Error ())
572
+ }
573
+ return shim.Success(queryResults)
574
+ }
575
+
576
+
577
+ The following example is a peer command which calls queryMarblesWithPagination
578
+ with a pageSize of ` ` 3` ` and no bookmark specified.
579
+
580
+ .. tip:: When no bookmark is specified, the query starts with the " first"
581
+ page of records.
582
+
583
+ :guilabel:` Try it yourself`
584
+
585
+ .. code:: bash
586
+
587
+ // Rich Query with index name explicitly specified and a page size of 3:
588
+ peer chaincode query -C $CHANNEL_NAME -n marbles -c ' {"Args":["queryMarblesWithPagination", "{\"selector\":{\"docType\":\"marble\",\"owner\":\"tom\"}, \"use_index\":[\"_design/indexOwnerDoc\", \"indexOwner\"]}","3",""]}'
589
+
590
+ The following response is received (carriage returns added for clarity), three
591
+ of the five marbles are returned because the ` ` pagsize` ` was set to ` ` 3` ` :
592
+
593
+ .. code:: bash
594
+
595
+ [{" Key" :" marble1" , " Record" :{" color" :" blue" ," docType" :" marble" ," name" :" marble1" ," owner" :" tom" ," size" :35}},
596
+ {" Key" :" marble2" , " Record" :{" color" :" yellow" ," docType" :" marble" ," name" :" marble2" ," owner" :" tom" ," size" :35}},
597
+ {" Key" :" marble3" , " Record" :{" color" :" green" ," docType" :" marble" ," name" :" marble3" ," owner" :" tom" ," size" :20}}]
598
+ [{" ResponseMetadata" :{" RecordsCount" :" 3" ,
599
+ " Bookmark" :" g1AAAABLeJzLYWBgYMpgSmHgKy5JLCrJTq2MT8lPzkzJBYqz5yYWJeWkGoOkOWDSOSANIFk2iCyIyVySn5uVBQAGEhRz" }}]
600
+
601
+ .. note:: Bookmarks are uniquely generated by CouchDB for each query and
602
+ represent a placeholder in the result set. Pass the
603
+ returned bookmark on the subsequent iteration of the query to
604
+ retrieve the next set of results.
605
+
606
+ The following is a peer command to call queryMarblesWithPagination with a
607
+ pageSize of ` ` 3` ` . Notice this time, the query includes the bookmark returned
608
+ from the previous query.
609
+
610
+ :guilabel:` Try it yourself`
611
+
612
+ .. code:: bash
613
+
614
+ peer chaincode query -C $CHANNEL_NAME -n marbles -c ' {"Args":["queryMarblesWithPagination", "{\"selector\":{\"docType\":\"marble\",\"owner\":\"tom\"}, \"use_index\":[\"_design/indexOwnerDoc\", \"indexOwner\"]}","3","g1AAAABLeJzLYWBgYMpgSmHgKy5JLCrJTq2MT8lPzkzJBYqz5yYWJeWkGoOkOWDSOSANIFk2iCyIyVySn5uVBQAGEhRz"]}'
615
+
616
+ The following response is received (carriage returns added for clarity). The
617
+ last two records are retrieved:
618
+
619
+ .. code:: bash
620
+
621
+ [{" Key" :" marble4" , " Record" :{" color" :" purple" ," docType" :" marble" ," name" :" marble4" ," owner" :" tom" ," size" :20}},
622
+ {" Key" :" marble5" , " Record" :{" color" :" blue" ," docType" :" marble" ," name" :" marble5" ," owner" :" tom" ," size" :40}}]
623
+ [{" ResponseMetadata" :{" RecordsCount" :" 2" ,
624
+ " Bookmark" :" g1AAAABLeJzLYWBgYMpgSmHgKy5JLCrJTq2MT8lPzkzJBYqz5yYWJeWkmoKkOWDSOSANIFk2iCyIyVySn5uVBQAGYhR1" }}]
625
+
626
+ The final command is a peer command to call queryMarblesWithPagination with
627
+ a pageSize of ` ` 3` ` and with the bookmark from the previous query.
628
+
629
+ :guilabel:` Try it yourself`
630
+
631
+ .. code:: bash
632
+
633
+ peer chaincode query -C $CHANNEL_NAME -n marbles -c ' {"Args":["queryMarblesWithPagination", "{\"selector\":{\"docType\":\"marble\",\"owner\":\"tom\"}, \"use_index\":[\"_design/indexOwnerDoc\", \"indexOwner\"]}","3","g1AAAABLeJzLYWBgYMpgSmHgKy5JLCrJTq2MT8lPzkzJBYqz5yYWJeWkmoKkOWDSOSANIFk2iCyIyVySn5uVBQAGYhR1"]}'
634
+
635
+ The following response is received (carriage returns added for clarity).
636
+ No records are returned, indicating that all pages have been retrieved:
637
+
638
+ .. code:: bash
639
+
640
+ []
641
+ [{" ResponseMetadata" :{" RecordsCount" :" 0" ,
642
+ " Bookmark" :" g1AAAABLeJzLYWBgYMpgSmHgKy5JLCrJTq2MT8lPzkzJBYqz5yYWJeWkmoKkOWDSOSANIFk2iCyIyVySn5uVBQAGYhR1" }}]
643
+
644
+ For an example of how a client application can iterate over
645
+ the result sets using pagination, search for the ` ` getQueryResultForQueryStringWithPagination` `
646
+ function in the ` Marbles sample < https://github.com/hyperledger/fabric-samples/blob/master/chaincode/marbles02/go/marbles_chaincode.go> ` __.
647
+
498
648
.. _cdb-update-index:
499
649
500
650
Update an Index
0 commit comments