github.com/kaituanwang/hyperledger@v2.0.1+incompatible/docs/source/couchdb_tutorial.rst (about) 1 2 Using CouchDB 3 ============= 4 5 This tutorial will describe the steps required to use the CouchDB as the state 6 database with Hyperledger Fabric. By now, you should be familiar with Fabric 7 concepts and have explored some of the samples and tutorials. 8 9 .. note:: These instructions use the new Fabric chaincode lifecycle introduced 10 in the Fabric v2.0 release. If you would like to use the previous 11 lifecycle model to use indexes with chaincode, visit the v1.4 12 version of the `Using CouchDB <https://hyperledger-fabric.readthedocs.io/en/release-1.4/couchdb_tutorial.html>`__. 13 14 The tutorial will take you through the following steps: 15 16 #. :ref:`cdb-enable-couch` 17 #. :ref:`cdb-create-index` 18 #. :ref:`cdb-add-index` 19 #. :ref:`cdb-install-deploy` 20 #. :ref:`cdb-query` 21 #. :ref:`cdb-best` 22 #. :ref:`cdb-pagination` 23 #. :ref:`cdb-update-index` 24 #. :ref:`cdb-delete-index` 25 26 For a deeper dive into CouchDB refer to :doc:`couchdb_as_state_database` 27 and for more information on the Fabric ledger refer to the `Ledger <ledger/ledger.html>`_ 28 topic. Follow the tutorial below for details on how to leverage CouchDB in your 29 blockchain network. 30 31 Throughout this tutorial, we will use the `Marbles sample <https://github.com/hyperledger/fabric-samples/blob/master/chaincode/marbles02/go/marbles_chaincode.go>`__ 32 as our use case to demonstrate how to use CouchDB with Fabric and will deploy 33 Marbles to the Fabric test network. You should have completed the task 34 :doc:`install`. 35 36 Why CouchDB? 37 ~~~~~~~~~~~~ 38 39 Fabric supports two types of peer databases. LevelDB is the default state 40 database embedded in the peer node. LevelDB stores chaincode data as simple 41 key-value pairs and only supports key, key range, and composite key queries. 42 CouchDB is an optional, alternate state database that allows you to model data 43 on the ledger as JSON and issue rich queries against data values rather than 44 the keys. CouchDB also allows you to deploy indexes with your chaincode to make 45 queries more efficient and enable you to query large datasets. 46 47 In order to leverage the benefits of CouchDB, namely content-based JSON 48 queries, your data must be modeled in JSON format. You must decide whether to use 49 LevelDB or CouchDB before setting up your network. Switching a peer from using 50 LevelDB to CouchDB is not supported due to data compatibility issues. All peers 51 on the network must use the same database type. If you have a mix of JSON and 52 binary data values, you can still use CouchDB, however the binary values can 53 only be queried based on key, key range, and composite key queries. 54 55 .. _cdb-enable-couch: 56 57 Enable CouchDB in Hyperledger Fabric 58 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 59 60 CouchDB runs as a separate database process alongside the peer. There 61 are additional considerations in terms of setup, management, and operations. 62 A Docker image of `CouchDB <https://hub.docker.com/_/couchdb/>`__ 63 is available and we recommend that it be run on the same server as the 64 peer. You will need to setup one CouchDB container per peer 65 and update each peer container by changing the configuration found in 66 ``core.yaml`` to point to the CouchDB container. The ``core.yaml`` 67 file must be located in the directory specified by the environment variable 68 FABRIC_CFG_PATH: 69 70 * For Docker deployments, ``core.yaml`` is pre-configured and located in the peer 71 container ``FABRIC_CFG_PATH`` folder. However, when using Docker environments, 72 you typically pass environment variables by editing the 73 ``docker-compose-couch.yaml`` to override the core.yaml 74 75 * For native binary deployments, ``core.yaml`` is included with the release artifact 76 distribution. 77 78 Edit the ``stateDatabase`` section of ``core.yaml``. Specify ``CouchDB`` as the 79 ``stateDatabase`` and fill in the associated ``couchDBConfig`` properties. For 80 more information, see `CouchDB configuration <couchdb_as_state_database.html#couchdb-configuration>`__. 81 82 .. _cdb-create-index: 83 84 Create an index 85 ~~~~~~~~~~~~~~~ 86 87 Why are indexes important? 88 89 Indexes allow a database to be queried without having to examine every row 90 with every query, making them run faster and more efficiently. Normally, 91 indexes are built for frequently occurring query criteria allowing the data to 92 be queried more efficiently. To leverage the major benefit of CouchDB -- the 93 ability to perform rich queries against JSON data -- indexes are not required, 94 but they are strongly recommended for performance. Also, if sorting is required 95 in a query, CouchDB requires an index of the sorted fields. 96 97 .. note:: 98 99 Rich queries that do not have an index will work but may throw a warning 100 in the CouchDB log that the index was not found. However, if a rich query 101 includes a sort specification, then an index on that field is required; 102 otherwise, the query will fail and an error will be thrown. 103 104 To demonstrate building an index, we will use the data from the `Marbles 105 sample <https://github.com/hyperledger/fabric-samples/blob/master/chaincode/marbles02/go/marbles_chaincode.go>`__. 106 In this example, the Marbles data structure is defined as: 107 108 .. code:: javascript 109 110 type marble struct { 111 ObjectType string `json:"docType"` //docType is used to distinguish the various types of objects in state database 112 Name string `json:"name"` //the field tags are needed to keep case from bouncing around 113 Color string `json:"color"` 114 Size int `json:"size"` 115 Owner string `json:"owner"` 116 } 117 118 119 In this structure, the attributes (``docType``, ``name``, ``color``, ``size``, 120 ``owner``) define the ledger data associated with the asset. The attribute 121 ``docType`` is a pattern used in the chaincode to differentiate different data 122 types that may need to be queried separately. When using CouchDB, it 123 recommended to include this ``docType`` attribute to distinguish each type of 124 document in the chaincode namespace. (Each chaincode is represented as its own 125 CouchDB database, that is, each chaincode has its own namespace for keys.) 126 127 With respect to the Marbles data structure, ``docType`` is used to identify 128 that this document/asset is a marble asset. Potentially there could be other 129 documents/assets in the chaincode database. The documents in the database are 130 searchable against all of these attribute values. 131 132 When defining an index for use in chaincode queries, each one must be defined 133 in its own text file with the extension `*.json` and the index definition must 134 be formatted in the CouchDB index JSON format. 135 136 To define an index, three pieces of information are required: 137 138 * `fields`: these are the frequently queried fields 139 * `name`: name of the index 140 * `type`: always json in this context 141 142 For example, a simple index named ``foo-index`` for a field named ``foo``. 143 144 .. code:: json 145 146 { 147 "index": { 148 "fields": ["foo"] 149 }, 150 "name" : "foo-index", 151 "type" : "json" 152 } 153 154 Optionally the design document attribute ``ddoc`` can be specified on the index 155 definition. A `design document <http://guide.couchdb.org/draft/design.html>`__ is 156 CouchDB construct designed to contain indexes. Indexes can be grouped into 157 design documents for efficiency but CouchDB recommends one index per design 158 document. 159 160 .. tip:: When defining an index it is a good practice to include the ``ddoc`` 161 attribute and value along with the index name. It is important to 162 include this attribute to ensure that you can update the index later 163 if needed. Also it gives you the ability to explicitly specify which 164 index to use on a query. 165 166 167 Here is another example of an index definition from the Marbles sample with 168 the index name ``indexOwner`` using multiple fields ``docType`` and ``owner`` 169 and includes the ``ddoc`` attribute: 170 171 .. _indexExample: 172 173 .. code:: json 174 175 { 176 "index":{ 177 "fields":["docType","owner"] // Names of the fields to be queried 178 }, 179 "ddoc":"indexOwnerDoc", // (optional) Name of the design document in which the index will be created. 180 "name":"indexOwner", 181 "type":"json" 182 } 183 184 In the example above, if the design document ``indexOwnerDoc`` does not already 185 exist, it is automatically created when the index is deployed. An index can be 186 constructed with one or more attributes specified in the list of fields and 187 any combination of attributes can be specified. An attribute can exist in 188 multiple indexes for the same docType. In the following example, ``index1`` 189 only includes the attribute ``owner``, ``index2`` includes the attributes 190 ``owner and color`` and ``index3`` includes the attributes ``owner, color and 191 size``. Also, notice each index definition has its own ``ddoc`` value, following 192 the CouchDB recommended practice. 193 194 .. code:: json 195 196 { 197 "index":{ 198 "fields":["owner"] // Names of the fields to be queried 199 }, 200 "ddoc":"index1Doc", // (optional) Name of the design document in which the index will be created. 201 "name":"index1", 202 "type":"json" 203 } 204 205 { 206 "index":{ 207 "fields":["owner", "color"] // Names of the fields to be queried 208 }, 209 "ddoc":"index2Doc", // (optional) Name of the design document in which the index will be created. 210 "name":"index2", 211 "type":"json" 212 } 213 214 { 215 "index":{ 216 "fields":["owner", "color", "size"] // Names of the fields to be queried 217 }, 218 "ddoc":"index3Doc", // (optional) Name of the design document in which the index will be created. 219 "name":"index3", 220 "type":"json" 221 } 222 223 224 In general, you should model index fields to match the fields that will be used 225 in query filters and sorts. For more details on building an index in JSON 226 format refer to the `CouchDB documentation <http://docs.couchdb.org/en/latest/api/database/find.html#db-index>`__. 227 228 A final word on indexing, Fabric takes care of indexing the documents in the 229 database using a pattern called ``index warming``. CouchDB does not typically 230 index new or updated documents until the next query. Fabric ensures that 231 indexes stay 'warm' by requesting an index update after every block of data is 232 committed. This ensures queries are fast because they do not have to index 233 documents before running the query. This process keeps the index current 234 and refreshed every time new records are added to the state database. 235 236 .. _cdb-add-index: 237 238 239 Add the index to your chaincode folder 240 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 241 242 Once you finalize an index, you need to package it with your chaincode for 243 deployment by placing it in the appropriate metadata folder. You can install the 244 chaincode using the :doc:`commands/peerlifecycle` command. The JSON index files 245 must be located under the path ``META-INF/statedb/couchdb/indexes`` which is 246 located inside the directory where the chaincode resides. 247 248 The `Marbles sample <https://github.com/hyperledger/fabric-samples/tree/master/chaincode/marbles02/go>`__ below illustrates how the index 249 is packaged with the chaincode. 250 251 .. image:: images/couchdb_tutorial_pkg_example.png 252 :scale: 100% 253 :align: center 254 :alt: Marbles Chaincode Index Package 255 256 This sample includes one index named indexOwnerDoc: 257 258 .. code:: json 259 260 {"index":{"fields":["docType","owner"]},"ddoc":"indexOwnerDoc", "name":"indexOwner","type":"json"} 261 262 263 Start the network 264 ----------------- 265 266 :guilabel:`Try it yourself` 267 268 269 We will bring up the Fabric test network and use it to deploy the marbles 270 chainocde. Use the following command to navigate to the `test-network` directory 271 in the Fabric samples: 272 273 .. code:: bash 274 275 cd fabric-samples/test-network 276 277 For this tutorial, we want to operate from a known initial state. The following 278 command will kill any active or stale Docker containers and remove previously 279 generated artifacts: 280 281 .. code:: bash 282 283 ./network.sh down 284 285 If you have not run through the tutorial before, you will need to vendor the 286 chaincode dependencies before we can deploy it to the network. Run the 287 following commands: 288 289 .. code:: bash 290 291 cd ../chaincode/marbles02/go 292 GO111MODULE=on go mod vendor 293 cd ../../../test-network 294 295 From the `test-network` directory, deploy the test network with CouchDB with the 296 following command: 297 298 .. code:: bash 299 300 ./network.sh up createChannel -s couchdb 301 302 This will create two fabric peer nodes that use CouchDB as the state database. 303 It will also create one ordering node and a single channel named 304 ``mychannel``. 305 306 .. _cdb-install-deploy: 307 308 Install and define the Chaincode 309 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 310 311 Client applications interact with the blockchain ledger through chaincode. 312 Therefore we need to install a chaincode on every peer that will execute and 313 endorse our transactions. However, before we can interact with our chaincode, 314 the members of the channel need to agree on a chaincode definition that 315 establishes chaincode governance. In the previous section, we demonstrated how 316 to add the index to the chaincode folder so that the index is deployed with 317 the chaincode. 318 319 The chaincode needs to be packaged before it can be installed on our peers. 320 We can use the `peer lifecycle chaincode package <commands/peerlifecycle.html#peer-lifecycle-chaincode-package>`__ command 321 to package the marbles chaincode. 322 323 :guilabel:`Try it yourself` 324 325 1. After you start the test network, copy and paste the following environment 326 variables in your CLI to interact with the network as the Org1 admin. Make sure 327 that you are in the `test-network` directory. 328 329 .. code:: bash 330 331 export PATH=${PWD}/../bin:${PWD}:$PATH 332 export FABRIC_CFG_PATH=${PWD}/../config/ 333 export CORE_PEER_TLS_ENABLED=true 334 export CORE_PEER_LOCALMSPID="Org1MSP" 335 export CORE_PEER_TLS_ROOTCERT_FILE=${PWD}/organizations/peerOrganizations/org1.example.com/peers/peer0.org1.example.com/tls/ca.crt 336 export CORE_PEER_MSPCONFIGPATH=${PWD}/organizations/peerOrganizations/org1.example.com/users/Admin@org1.example.com/msp 337 export CORE_PEER_ADDRESS=localhost:7051 338 339 2. Use the following command to package the marbles chaincode: 340 341 .. code:: bash 342 343 peer lifecycle chaincode package marbles.tar.gz --path ../chaincode/marbles02/go --lang golang --label marbles_1 344 345 This command will create a chaincode package named marbles.tar.gz. 346 347 3. Use the following command to install the chaincode package onto the peer 348 ``peer0.org1.example.com``: 349 350 .. code:: bash 351 352 peer lifecycle chaincode install marbles.tar.gz 353 354 A successful install command will return the chaincode identifier, similar to 355 the response below: 356 357 .. code:: bash 358 359 2019-04-22 18:47:38.312 UTC [cli.lifecycle.chaincode] submitInstallProposal -> INFO 001 Installed remotely: response:<status:200 payload:"\nJmarbles_1:0907c1f3d3574afca69946e1b6132691d58c2f5c5703df7fc3b692861e92ecd3\022\tmarbles_1" > 360 2019-04-22 18:47:38.312 UTC [cli.lifecycle.chaincode] submitInstallProposal -> INFO 002 Chaincode code package identifier: marbles_1:0907c1f3d3574afca69946e1b6132691d58c2f5c5703df7fc3b692861e92ecd3 361 362 After installing the chaincode on ``peer0.org1.example.com``, we need to approve 363 a chaincode definition for Org1. 364 365 4. Use the following command to query your peer for the package ID of the 366 installed chaincode. 367 368 .. code:: bash 369 370 peer lifecycle chaincode queryinstalled 371 372 The command will return the same package identifier as the install command. 373 You should see output similar to the following: 374 375 .. code:: bash 376 377 Installed chaincodes on peer: 378 Package ID: marbles_1:60ec9430b221140a45b96b4927d1c3af736c1451f8d432e2a869bdbf417f9787, Label: marbles_1 379 380 5. Declare the package ID as an environment variable. Paste the package ID of 381 marbles_1 returned by the ``peer lifecycle chaincode queryinstalled`` command 382 into the command below. The package ID may not be the same for all users, so 383 you need to complete this step using the package ID returned from your console. 384 385 .. code:: bash 386 387 export CC_PACKAGE_ID=marbles_1:60ec9430b221140a45b96b4927d1c3af736c1451f8d432e2a869bdbf417f9787 388 389 6. Use the following command to approve a definition of the marbles chaincode 390 for Org1. 391 392 .. code:: bash 393 394 export ORDERER_CA=${PWD}/organizations/ordererOrganizations/example.com/orderers/orderer.example.com/msp/tlscacerts/tlsca.example.com-cert.pem 395 peer lifecycle chaincode approveformyorg -o localhost:7050 --ordererTLSHostnameOverride orderer.example.com --channelID mychannel --name marbles --version 1.0 --signature-policy "OR('Org1MSP.member','Org2MSP.member')" --init-required --package-id $CC_PACKAGE_ID --sequence 1 --tls true --cafile $ORDERER_CA 396 397 When the command completes successfully you should see something similar to : 398 399 .. code:: bash 400 401 2020-01-07 16:24:20.886 EST [chaincodeCmd] ClientWait -> INFO 001 txid [560cb830efa1272c85d2f41a473483a25f3b12715d55e22a69d55abc46581415] committed with status (VALID) at 402 403 We need a majority of organizations to approve a chaincode definition before 404 it can be committed to the channel. This implies that we need Org2 to approve 405 the chaincode definition as well. Because we do not need Org2 to endorse the 406 chaincode and did not install the package on any Org2 peers, we do not need to 407 provide a packageID as part of the chaincode definition. 408 409 7. Use the CLI to operate as the Org2 admin. Copy and paste the following block 410 of commands as a group into the peer container and run them all at once. 411 412 .. code:: bash 413 414 export CORE_PEER_LOCALMSPID="Org2MSP" 415 export CORE_PEER_TLS_ROOTCERT_FILE=${PWD}/organizations/peerOrganizations/org2.example.com/peers/peer0.org2.example.com/tls/ca.crt 416 export CORE_PEER_MSPCONFIGPATH=${PWD}/organizations/peerOrganizations/org2.example.com/users/Admin@org2.example.com/msp 417 export CORE_PEER_ADDRESS=localhost:9051 418 419 8. Use the following command to approve the chaincode definition for Org2: 420 421 .. code:: bash 422 423 peer lifecycle chaincode approveformyorg -o localhost:7050 --ordererTLSHostnameOverride orderer.example.com --channelID mychannel --name marbles --version 1.0 --signature-policy "OR('Org1MSP.member','Org2MSP.member')" --init-required --sequence 1 --tls true --cafile $ORDERER_CA 424 425 9. We can now use the `peer lifecycle chaincode commit <commands/peerlifecycle.html#peer-lifecycle-chaincode-commit>`__ command 426 to commit the chaincode definition to the channel: 427 428 .. code:: bash 429 430 export ORDERER_CA=${PWD}/organizations/ordererOrganizations/example.com/orderers/orderer.example.com/msp/tlscacerts/tlsca.example.com-cert.pem 431 export ORG1_CA=${PWD}/organizations/peerOrganizations/org1.example.com/peers/peer0.org1.example.com/tls/ca.crt 432 export ORG2_CA=${PWD}/organizations/peerOrganizations/org2.example.com/peers/peer0.org2.example.com/tls/ca.crt 433 peer lifecycle chaincode commit -o localhost:7050 --ordererTLSHostnameOverride orderer.example.com --channelID mychannel --name marbles --version 1.0 --sequence 1 --signature-policy "OR('Org1MSP.member','Org2MSP.member')" --init-required --tls true --cafile $ORDERER_CA --peerAddresses localhost:7051 --tlsRootCertFiles $ORG1_CA --peerAddresses localhost:9051 --tlsRootCertFiles $ORG2_CA 434 435 When the commit transaction completes successfully you should see something 436 similar to: 437 438 .. code:: bash 439 440 2019-04-22 18:57:34.274 UTC [chaincodeCmd] ClientWait -> INFO 001 txid [3da8b0bb8e128b5e1b6e4884359b5583dff823fce2624f975c69df6bce614614] committed with status (VALID) at peer0.org2.example.com:9051 441 2019-04-22 18:57:34.709 UTC [chaincodeCmd] ClientWait -> INFO 002 txid [3da8b0bb8e128b5e1b6e4884359b5583dff823fce2624f975c69df6bce614614] committed with status (VALID) at peer0.org1.example.com:7051 442 443 10. Because the marbles chaincode contains an initialization function, we need to 444 use the `peer chaincode invoke <commands/peerchaincode.html?%20chaincode%20instantiate#peer-chaincode-invoke>`__ command 445 to invoke ``Init()`` before we can use other functions in the chaincode: 446 447 .. code:: bash 448 449 peer chaincode invoke -o localhost:7050 --ordererTLSHostnameOverride orderer.example.com --channelID mychannel --name marbles --isInit --tls true --cafile $ORDERER_CA --peerAddresses localhost:7051 --tlsRootCertFiles $ORG1_CA -c '{"Args":["Init"]}' 450 451 Verify index was deployed 452 ------------------------- 453 454 Indexes will be deployed to each peer's CouchDB state database once the 455 chaincode has been installed on the peer and deployed to the channel. You can 456 verify that the CouchDB index was created successfully by examining the peer log 457 in the Docker container. 458 459 :guilabel:`Try it yourself` 460 461 To view the logs in the peer Docker container, open a new Terminal window and 462 run the following command to grep for message confirmation that the index was 463 created. 464 465 :: 466 467 docker logs peer0.org1.example.com 2>&1 | grep "CouchDB index" 468 469 470 You should see a result that looks like the following: 471 472 :: 473 474 [couchdb] CreateIndex -> INFO 0be Created CouchDB index [indexOwner] in state database [mychannel_marbles] using design document [_design/indexOwnerDoc] 475 476 .. note:: If you installed Marbles on a different peer than ``peer0.org1.example.com``, 477 you may need to replace it with the name of a different peer where 478 Marbles was installed. 479 480 .. _cdb-query: 481 482 Query the CouchDB State Database 483 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 484 485 Now that the index has been defined in the JSON file and deployed alongside the 486 chaincode, chaincode functions can execute JSON queries against the CouchDB 487 state database, and thereby peer commands can invoke the chaincode functions. 488 489 Specifying an index name on a query is optional. If not specified, and an index 490 already exists for the fields being queried, the existing index will be 491 automatically used. 492 493 .. tip:: It is a good practice to explicitly include an index name on a 494 query using the ``use_index`` keyword. Without it, CouchDB may pick a 495 less optimal index. Also CouchDB may not use an index at all and you 496 may not realize it, at the low volumes during testing. Only upon 497 higher volumes you may realize slow performance because CouchDB is not 498 using an index and you assumed it was. 499 500 501 Build the query in chaincode 502 ---------------------------- 503 504 You can perform complex rich queries against the data on the ledger using 505 queries defined within your chaincode. The `marbles02 sample <https://github.com/hyperledger/fabric-samples/blob/master/chaincode/marbles02/go/marbles_chaincode.go>`__ 506 includes two rich query functions: 507 508 * **queryMarbles** -- 509 510 Example of an **ad hoc rich query**. This is a query 511 where a (selector) string can be passed into the function. This query 512 would be useful to client applications that need to dynamically build 513 their own selectors at runtime. For more information on selectors refer 514 to `CouchDB selector syntax <http://docs.couchdb.org/en/latest/api/database/find.html#find-selectors>`__. 515 516 517 * **queryMarblesByOwner** -- 518 519 Example of a **parameterized query** where the 520 query logic is baked into the chaincode. In this case the function accepts 521 a single argument, the marble owner. It then queries the state database for 522 JSON documents matching the docType of “marble” and the owner id using the 523 JSON query syntax. 524 525 526 Run the query using the peer command 527 ------------------------------------ 528 529 In absence of a client application, we can use the peer command to test the 530 queries defined in the chaincode. We will customize the `peer chaincode query <commands/peerchaincode.html?%20chaincode%20query#peer-chaincode-query>`__ 531 command to use the Marbles index ``indexOwner`` and query for all marbles owned 532 by "tom" using the ``queryMarbles`` function. 533 534 :guilabel:`Try it yourself` 535 536 Before querying the database, we should add some data. Run the following 537 command as Org1 to create a marble owned by "tom": 538 539 .. code:: bash 540 541 export CORE_PEER_LOCALMSPID="Org1MSP" 542 export CORE_PEER_TLS_ROOTCERT_FILE=${PWD}/organizations/peerOrganizations/org1.example.com/peers/peer0.org1.example.com/tls/ca.crt 543 export CORE_PEER_MSPCONFIGPATH=${PWD}/organizations/peerOrganizations/org1.example.com/users/Admin@org1.example.com/msp 544 export CORE_PEER_ADDRESS=localhost:7051 545 peer chaincode invoke -o localhost:7050 --ordererTLSHostnameOverride orderer.example.com --tls --cafile ${PWD}/organizations/ordererOrganizations/example.com/orderers/orderer.example.com/msp/tlscacerts/tlsca.example.com-cert.pem -C mychannel -n marbles -c '{"Args":["initMarble","marble1","blue","35","tom"]}' 546 547 After an index has been deployed when the chaincode is initialized, it will 548 automatically be utilized by chaincode queries. CouchDB can determine which 549 index to use based on the fields being queried. If an index exists for the 550 query criteria it will be used. However the recommended approach is to 551 specify the ``use_index`` keyword on the query. The peer command below is an 552 example of how to specify the index explicitly in the selector syntax by 553 including the ``use_index`` keyword: 554 555 .. code:: bash 556 557 // Rich Query with index name explicitly specified: 558 peer chaincode query -C mychannel -n marbles -c '{"Args":["queryMarbles", "{\"selector\":{\"docType\":\"marble\",\"owner\":\"tom\"}, \"use_index\":[\"_design/indexOwnerDoc\", \"indexOwner\"]}"]}' 559 560 Delving into the query command above, there are three arguments of interest: 561 562 * ``queryMarbles`` 563 564 Name of the function in the Marbles chaincode. Notice a `shim <https://godoc.org/github.com/hyperledger/fabric-chaincode-go/shim>`__ 565 ``shim.ChaincodeStubInterface`` is used to access and modify the ledger. The 566 ``getQueryResultForQueryString()`` passes the queryString to the shim API ``getQueryResult()``. 567 568 .. code:: bash 569 570 func (t *SimpleChaincode) queryMarbles(stub shim.ChaincodeStubInterface, args []string) pb.Response { 571 572 // 0 573 // "queryString" 574 if len(args) < 1 { 575 return shim.Error("Incorrect number of arguments. Expecting 1") 576 } 577 578 queryString := args[0] 579 580 queryResults, err := getQueryResultForQueryString(stub, queryString) 581 if err != nil { 582 return shim.Error(err.Error()) 583 } 584 return shim.Success(queryResults) 585 } 586 587 * ``{"selector":{"docType":"marble","owner":"tom"}`` 588 589 This is an example of an **ad hoc selector** string which finds all documents 590 of type ``marble`` where the ``owner`` attribute has a value of ``tom``. 591 592 593 * ``"use_index":["_design/indexOwnerDoc", "indexOwner"]`` 594 595 Specifies both the design doc name ``indexOwnerDoc`` and index name 596 ``indexOwner``. In this example the selector query explicitly includes the 597 index name, specified by using the ``use_index`` keyword. Recalling the 598 index definition above :ref:`cdb-create-index`, it contains a design doc, 599 ``"ddoc":"indexOwnerDoc"``. With CouchDB, if you plan to explicitly include 600 the index name on the query, then the index definition must include the 601 ``ddoc`` value, so it can be referenced with the ``use_index`` keyword. 602 603 604 The query runs successfully and the index is leveraged with the following results: 605 606 .. code:: json 607 608 Query Result: [{"Key":"marble1", "Record":{"color":"blue","docType":"marble","name":"marble1","owner":"tom","size":35}}] 609 610 .. _cdb-best: 611 612 Use best practices for queries and indexes 613 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 614 615 Queries that use indexes will complete faster, without having to scan the full 616 database in couchDB. Understanding indexes will allow you to write your queries 617 for better performance and help your application handle larger amounts 618 of data or blocks on your network. 619 620 It is also important to plan the indexes you install with your chaincode. You 621 should install only a few indexes per chaincode that support most of your queries. 622 Adding too many indexes, or using an excessive number of fields in an index, will 623 degrade the performance of your network. This is because the indexes are updated 624 after each block is committed. The more indexes need to be updated through 625 "index warming", the longer it will take for transactions to complete. 626 627 The examples in this section will help demonstrate how queries use indexes and 628 what type of queries will have the best performance. Remember the following 629 when writing your queries: 630 631 * All fields in the index must also be in the selector or sort sections of your query 632 for the index to be used. 633 * More complex queries will have a lower performance and will be less likely to 634 use an index. 635 * You should try to avoid operators that will result in a full table scan or a 636 full index scan such as ``$or``, ``$in`` and ``$regex``. 637 638 In the previous section of this tutorial, you issued the following query against 639 the marbles chaincode: 640 641 .. code:: bash 642 643 // Example one: query fully supported by the index 644 peer chaincode query -C $CHANNEL_NAME -n marbles -c '{"Args":["queryMarbles", "{\"selector\":{\"docType\":\"marble\",\"owner\":\"tom\"}, \"use_index\":[\"indexOwnerDoc\", \"indexOwner\"]}"]}' 645 646 The marbles chaincode was installed with the ``indexOwnerDoc`` index: 647 648 .. code:: json 649 650 {"index":{"fields":["docType","owner"]},"ddoc":"indexOwnerDoc", "name":"indexOwner","type":"json"} 651 652 Notice that both the fields in the query, ``docType`` and ``owner``, are 653 included in the index, making it a fully supported query. As a result this 654 query will be able to use the data in the index, without having to search the 655 full database. Fully supported queries such as this one will return faster than 656 other queries from your chaincode. 657 658 If you add extra fields to the query above, it will still use the index. 659 However, the query will additionally have to scan the indexed data for the 660 extra fields, resulting in a longer response time. As an example, the query 661 below will still use the index, but will take a longer time to return than the 662 previous example. 663 664 .. code:: bash 665 666 // Example two: query fully supported by the index with additional data 667 peer chaincode query -C $CHANNEL_NAME -n marbles -c '{"Args":["queryMarbles", "{\"selector\":{\"docType\":\"marble\",\"owner\":\"tom\",\"color\":\"red\"}, \"use_index\":[\"/indexOwnerDoc\", \"indexOwner\"]}"]}' 668 669 A query that does not include all fields in the index will have to scan the full 670 database instead. For example, the query below searches for the owner, without 671 specifying the the type of item owned. Since the ownerIndexDoc contains both 672 the ``owner`` and ``docType`` fields, this query will not be able to use the 673 index. 674 675 .. code:: bash 676 677 // Example three: query not supported by the index 678 peer chaincode query -C $CHANNEL_NAME -n marbles -c '{"Args":["queryMarbles", "{\"selector\":{\"owner\":\"tom\"}, \"use_index\":[\"indexOwnerDoc\", \"indexOwner\"]}"]}' 679 680 In general, more complex queries will have a longer response time, and have a 681 lower chance of being supported by an index. Operators such as ``$or``, ``$in``, 682 and ``$regex`` will often cause the query to scan the full index or not use the 683 index at all. 684 685 As an example, the query below contains an ``$or`` term that will search for every 686 marble and every item owned by tom. 687 688 .. code:: bash 689 690 // Example four: query with $or supported by the index 691 peer chaincode query -C $CHANNEL_NAME -n marbles -c '{"Args":["queryMarbles", "{\"selector\":{"\$or\":[{\"docType\:\"marble\"},{\"owner\":\"tom\"}]}, \"use_index\":[\"indexOwnerDoc\", \"indexOwner\"]}"]}' 692 693 This query will still use the index because it searches for fields that are 694 included in ``indexOwnerDoc``. However, the ``$or`` condition in the query 695 requires a scan of all the items in the index, resulting in a longer response 696 time. 697 698 Below is an example of a complex query that is not supported by the index. 699 700 .. code:: bash 701 702 // Example five: Query with $or not supported by the index 703 peer chaincode query -C $CHANNEL_NAME -n marbles -c '{"Args":["queryMarbles", "{\"selector\":{"\$or\":[{\"docType\":\"marble\",\"owner\":\"tom\"},{"\color\":"\yellow\"}]}, \"use_index\":[\"indexOwnerDoc\", \"indexOwner\"]}"]}' 704 705 The query searches for all marbles owned by tom or any other items that are 706 yellow. This query will not use the index because it will need to search the 707 entire table to meet the ``$or`` condition. Depending the amount of data on your 708 ledger, this query will take a long time to respond or may timeout. 709 710 While it is important to follow best practices with your queries, using indexes 711 is not a solution for collecting large amounts of data. The blockchain data 712 structure is optimized to validate and confirm transactions and is not suited 713 for data analytics or reporting. If you want to build a dashboard as part 714 of your application or analyze the data from your network, the best practice is 715 to query an off chain database that replicates the data from your peers. This 716 will allow you to understand the data on the blockchain without degrading the 717 performance of your network or disrupting transactions. 718 719 You can use block or chaincode events from your application to write transaction 720 data to an off-chain database or analytics engine. For each block received, the block 721 listener application would iterate through the block transactions and build a data 722 store using the key/value writes from each valid transaction's ``rwset``. The 723 :doc:`peer_event_services` provide replayable events to ensure the integrity of 724 downstream data stores. For an example of how you can use an event listener to write 725 data to an external database, visit the `Off chain data sample <https://github.com/hyperledger/fabric-samples/tree/master/off_chain_data>`__ 726 in the Fabric Samples. 727 728 .. _cdb-pagination: 729 730 Query the CouchDB State Database With Pagination 731 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 732 733 When large result sets are returned by CouchDB queries, a set of APIs is 734 available which can be called by chaincode to paginate the list of results. 735 Pagination provides a mechanism to partition the result set by 736 specifying a ``pagesize`` and a start point -- a ``bookmark`` which indicates 737 where to begin the result set. The client application iteratively invokes the 738 chaincode that executes the query until no more results are returned. For more information refer to 739 this `topic on pagination with CouchDB <couchdb_as_state_database.html#couchdb-pagination>`__. 740 741 742 We will use the `Marbles sample <https://github.com/hyperledger/fabric-samples/blob/master/chaincode/marbles02/go/marbles_chaincode.go>`__ 743 function ``queryMarblesWithPagination`` to demonstrate how 744 pagination can be implemented in chaincode and the client application. 745 746 * **queryMarblesWithPagination** -- 747 748 Example of an **ad hoc rich query with pagination**. This is a query 749 where a (selector) string can be passed into the function similar to the 750 above example. In this case, a ``pageSize`` is also included with the query as 751 well as a ``bookmark``. 752 753 In order to demonstrate pagination, more data is required. This example assumes 754 that you have already added marble1 from above. Run the following commands in 755 the peer container to create four more marbles owned by "tom", to create a 756 total of five marbles owned by "tom": 757 758 :guilabel:`Try it yourself` 759 760 .. code:: bash 761 762 export CORE_PEER_LOCALMSPID="Org1MSP" 763 export CORE_PEER_TLS_ROOTCERT_FILE=${PWD}/organizations/peerOrganizations/org1.example.com/peers/peer0.org1.example.com/tls/ca.crt 764 export CORE_PEER_MSPCONFIGPATH=${PWD}/organizations/peerOrganizations/org1.example.com/users/Admin@org1.example.com/msp 765 export CORE_PEER_ADDRESS=localhost:7051 766 peer chaincode invoke -o localhost:7050 --ordererTLSHostnameOverride orderer.example.com --tls --cafile ${PWD}/organizations/ordererOrganizations/example.com/orderers/orderer.example.com/msp/tlscacerts/tlsca.example.com-cert.pem -C mychannel -n marbles -c '{"Args":["initMarble","marble2","yellow","35","tom"]}' 767 peer chaincode invoke -o localhost:7050 --ordererTLSHostnameOverride orderer.example.com --tls --cafile ${PWD}/organizations/ordererOrganizations/example.com/orderers/orderer.example.com/msp/tlscacerts/tlsca.example.com-cert.pem -C mychannel -n marbles -c '{"Args":["initMarble","marble3","green","20","tom"]}' 768 peer chaincode invoke -o localhost:7050 --ordererTLSHostnameOverride orderer.example.com --tls --cafile ${PWD}/organizations/ordererOrganizations/example.com/orderers/orderer.example.com/msp/tlscacerts/tlsca.example.com-cert.pem -C mychannel -n marbles -c '{"Args":["initMarble","marble4","purple","20","tom"]}' 769 peer chaincode invoke -o localhost:7050 --ordererTLSHostnameOverride orderer.example.com --tls --cafile ${PWD}/organizations/ordererOrganizations/example.com/orderers/orderer.example.com/msp/tlscacerts/tlsca.example.com-cert.pem -C mychannel -n marbles -c '{"Args":["initMarble","marble5","blue","40","tom"]}' 770 771 In addition to the arguments for the query in the previous example, 772 queryMarblesWithPagination adds ``pagesize`` and ``bookmark``. ``PageSize`` 773 specifies the number of records to return per query. The ``bookmark`` is an 774 "anchor" telling couchDB where to begin the page. (Each page of results returns 775 a unique bookmark.) 776 777 * ``queryMarblesWithPagination`` 778 779 Name of the function in the Marbles chaincode. Notice a `shim <https://godoc.org/github.com/hyperledger/fabric-chaincode-go/shim>`__ 780 ``shim.ChaincodeStubInterface`` is used to access and modify the ledger. The 781 ``getQueryResultForQueryStringWithPagination()`` passes the queryString along 782 with the pagesize and bookmark to the shim API ``GetQueryResultWithPagination()``. 783 784 .. code:: bash 785 786 func (t *SimpleChaincode) queryMarblesWithPagination(stub shim.ChaincodeStubInterface, args []string) pb.Response { 787 788 // 0 789 // "queryString" 790 if len(args) < 3 { 791 return shim.Error("Incorrect number of arguments. Expecting 3") 792 } 793 794 queryString := args[0] 795 //return type of ParseInt is int64 796 pageSize, err := strconv.ParseInt(args[1], 10, 32) 797 if err != nil { 798 return shim.Error(err.Error()) 799 } 800 bookmark := args[2] 801 802 queryResults, err := getQueryResultForQueryStringWithPagination(stub, queryString, int32(pageSize), bookmark) 803 if err != nil { 804 return shim.Error(err.Error()) 805 } 806 return shim.Success(queryResults) 807 } 808 809 810 The following example is a peer command which calls queryMarblesWithPagination 811 with a pageSize of ``3`` and no bookmark specified. 812 813 .. tip:: When no bookmark is specified, the query starts with the "first" 814 page of records. 815 816 :guilabel:`Try it yourself` 817 818 .. code:: bash 819 820 // Rich Query with index name explicitly specified and a page size of 3: 821 peer chaincode query -C $CHANNEL_NAME -n marbles -c '{"Args":["queryMarblesWithPagination", "{\"selector\":{\"docType\":\"marble\",\"owner\":\"tom\"}, \"use_index\":[\"_design/indexOwnerDoc\", \"indexOwner\"]}","3",""]}' 822 823 The following response is received (carriage returns added for clarity), three 824 of the five marbles are returned because the ``pagsize`` was set to ``3``: 825 826 .. code:: bash 827 828 [{"Key":"marble1", "Record":{"color":"blue","docType":"marble","name":"marble1","owner":"tom","size":35}}, 829 {"Key":"marble2", "Record":{"color":"yellow","docType":"marble","name":"marble2","owner":"tom","size":35}}, 830 {"Key":"marble3", "Record":{"color":"green","docType":"marble","name":"marble3","owner":"tom","size":20}}] 831 [{"ResponseMetadata":{"RecordsCount":"3", 832 "Bookmark":"g1AAAABLeJzLYWBgYMpgSmHgKy5JLCrJTq2MT8lPzkzJBYqz5yYWJeWkGoOkOWDSOSANIFk2iCyIyVySn5uVBQAGEhRz"}}] 833 834 .. note:: Bookmarks are uniquely generated by CouchDB for each query and 835 represent a placeholder in the result set. Pass the 836 returned bookmark on the subsequent iteration of the query to 837 retrieve the next set of results. 838 839 The following is a peer command to call queryMarblesWithPagination with a 840 pageSize of ``3``. Notice this time, the query includes the bookmark returned 841 from the previous query. 842 843 :guilabel:`Try it yourself` 844 845 .. code:: bash 846 847 peer chaincode query -C $CHANNEL_NAME -n marbles -c '{"Args":["queryMarblesWithPagination", "{\"selector\":{\"docType\":\"marble\",\"owner\":\"tom\"}, \"use_index\":[\"_design/indexOwnerDoc\", \"indexOwner\"]}","3","g1AAAABLeJzLYWBgYMpgSmHgKy5JLCrJTq2MT8lPzkzJBYqz5yYWJeWkGoOkOWDSOSANIFk2iCyIyVySn5uVBQAGEhRz"]}' 848 849 The following response is received (carriage returns added for clarity). The 850 last two records are retrieved: 851 852 .. code:: bash 853 854 [{"Key":"marble4", "Record":{"color":"purple","docType":"marble","name":"marble4","owner":"tom","size":20}}, 855 {"Key":"marble5", "Record":{"color":"blue","docType":"marble","name":"marble5","owner":"tom","size":40}}] 856 [{"ResponseMetadata":{"RecordsCount":"2", 857 "Bookmark":"g1AAAABLeJzLYWBgYMpgSmHgKy5JLCrJTq2MT8lPzkzJBYqz5yYWJeWkmoKkOWDSOSANIFk2iCyIyVySn5uVBQAGYhR1"}}] 858 859 The final command is a peer command to call queryMarblesWithPagination with 860 a pageSize of ``3`` and with the bookmark from the previous query. 861 862 :guilabel:`Try it yourself` 863 864 .. code:: bash 865 866 peer chaincode query -C $CHANNEL_NAME -n marbles -c '{"Args":["queryMarblesWithPagination", "{\"selector\":{\"docType\":\"marble\",\"owner\":\"tom\"}, \"use_index\":[\"_design/indexOwnerDoc\", \"indexOwner\"]}","3","g1AAAABLeJzLYWBgYMpgSmHgKy5JLCrJTq2MT8lPzkzJBYqz5yYWJeWkmoKkOWDSOSANIFk2iCyIyVySn5uVBQAGYhR1"]}' 867 868 The following response is received (carriage returns added for clarity). 869 No records are returned, indicating that all pages have been retrieved: 870 871 .. code:: bash 872 873 [] 874 [{"ResponseMetadata":{"RecordsCount":"0", 875 "Bookmark":"g1AAAABLeJzLYWBgYMpgSmHgKy5JLCrJTq2MT8lPzkzJBYqz5yYWJeWkmoKkOWDSOSANIFk2iCyIyVySn5uVBQAGYhR1"}}] 876 877 For an example of how a client application can iterate over 878 the result sets using pagination, search for the ``getQueryResultForQueryStringWithPagination`` 879 function in the `Marbles sample <https://github.com/hyperledger/fabric-samples/blob/master/chaincode/marbles02/go/marbles_chaincode.go>`__. 880 881 .. _cdb-update-index: 882 883 Update an Index 884 ~~~~~~~~~~~~~~~ 885 886 It may be necessary to update an index over time. The same index may exist in 887 subsequent versions of the chaincode that gets installed. In order for an index 888 to be updated, the original index definition must have included the design 889 document ``ddoc`` attribute and an index name. To update an index definition, 890 use the same index name but alter the index definition. Simply edit the index 891 JSON file and add or remove fields from the index. Fabric only supports the 892 index type JSON. Changing the index type is not supported. The updated 893 index definition gets redeployed to the peer’s state database when the chaincode 894 definition is committed to the channel. Changes to the index name or ``ddoc`` 895 attributes will result in a new index being created and the original index remains 896 unchanged in CouchDB until it is removed. 897 898 .. note:: If the state database has a significant volume of data, it will take 899 some time for the index to be re-built, during which time chaincode 900 invokes that issue queries may fail or timeout. 901 902 Iterating on your index definition 903 ---------------------------------- 904 905 If you have access to your peer's CouchDB state database in a development 906 environment, you can iteratively test various indexes in support of 907 your chaincode queries. Any changes to chaincode though would require 908 redeployment. Use the `CouchDB Fauxton interface <http://docs.couchdb.org/en/latest/fauxton/index.html>`__ or a command 909 line curl utility to create and update indexes. 910 911 .. note:: The Fauxton interface is a web UI for the creation, update, and 912 deployment of indexes to CouchDB. If you want to try out this 913 interface, there is an example of the format of the Fauxton version 914 of the index in Marbles sample. If you have deployed the test network 915 with CouchDB, the Fauxton interface can be loaded by opening a browser 916 and navigating to ``http://localhost:5984/_utils``. 917 918 Alternatively, if you prefer not use the Fauxton UI, the following is an example 919 of a curl command which can be used to create the index on the database 920 ``mychannel_marbles``: 921 922 .. code:: bash 923 924 // Index for docType, owner. 925 // Example curl command line to define index in the CouchDB channel_chaincode database 926 curl -i -X POST -H "Content-Type: application/json" -d 927 "{\"index\":{\"fields\":[\"docType\",\"owner\"]}, 928 \"name\":\"indexOwner\", 929 \"ddoc\":\"indexOwnerDoc\", 930 \"type\":\"json\"}" http://hostname:port/mychannel_marbles/_index 931 932 .. note:: If you are using the test network configured with CouchDB, replace 933 hostname:port with ``localhost:5984``. 934 935 .. _cdb-delete-index: 936 937 Delete an Index 938 ~~~~~~~~~~~~~~~ 939 940 Index deletion is not managed by Fabric tooling. If you need to delete an index, 941 manually issue a curl command against the database or delete it using the 942 Fauxton interface. 943 944 The format of the curl command to delete an index would be: 945 946 .. code:: bash 947 948 curl -X DELETE http://localhost:5984/{database_name}/_index/{design_doc}/json/{index_name} -H "accept: */*" -H "Host: localhost:5984" 949 950 951 To delete the index used in this tutorial, the curl command would be: 952 953 .. code:: bash 954 955 curl -X DELETE http://localhost:5984/mychannel_marbles/_index/indexOwnerDoc/json/indexOwner -H "accept: */*" -H "Host: localhost:5984" 956 957 958 959 .. Licensed under Creative Commons Attribution 4.0 International License 960 https://creativecommons.org/licenses/by/4.0/