此类型的变量不支持使用点进行索引如何解决_Hyperledger Fabric使用CouchDB

本教程详细介绍了如何在Hyperledger Fabric中启用和利用CouchDB的富查询功能。内容包括启用CouchDB,创建索引,将索引添加到chaincode,安装和实例化Chaincode,查询CouchDB状态数据库,以及索引的更新和删除。教程强调了索引的重要性,提供示例说明如何构建和使用索引以提高查询性能,并提供了最佳实践建议。
摘要由CSDN通过智能技术生成

本教程将介绍将CouchDB用作Hyperledger Fabric的状态数据库所需的步骤。到目前为止,您应该熟悉Fabric概念并探索了一些示例和教程。

在Fabric v2.0中作为Alpha功能引入的Fabric链代码生命周期不支持在CouchDB中使用索引。因此,本教程需要先前的生命周期过程来安装和实例化包含CouchDB索引的链代码。下载Fabric Samples的1.4版本以使用本教程。有关更多信息,请参阅将索引添加到chaincode文件夹。

本教程将指导您完成以下步骤:

  1. 在Hyperledger Fabric中启用CouchDB

  2. 创建索引

  3. 将索引添加到您的chaincode文件夹

  4. 安装并实例化Chaincode

  5. 查询CouchDB状态数据库

  6. 使用查询和索引的最佳实践

  7. 使用分页查询CouchDB状态数据库

  8. 更新索引

  9. 删除索引

要深入了解CouchDB,请将CouchDB称为状态数据库 ,有关Fabric分类帐的更多信息,请参阅Ledger 主题。请按照以下教程获取有关如何在区块链网络中利用CouchDB的详细信息。

在本教程中,我们将使用Marbles示例 作为我们的用例来演示如何将CouchDB与Fabric配合使用,并将Marbles部署到构建您的第一个网络(BYFN)教程网络。您应该已完成安装示例,二进制文件和Docker镜像的任务。但是,运行BYFN教程不是本教程的先决条件,而是在本教程中提供必要的命令以使用网络。

为何选择CouchDB?

Fabric支持两种类型的对等数据库。LevelDB是嵌入在对等节点中的默认状态数据库,它将链代码数据存储为简单的键值对,仅支持键,键范围和复合键查询。CouchDB是一个可选的备用状态数据库,当链代码数据值建模为JSON时,它支持富查询。当您要查询实际数据值内容而不是密钥时,富查询对大型索引数据存储更灵活,更高效。CouchDB是一个JSON文档数据存储区而不是纯键值存储区,因此可以索引数据库中文档的内容。

为了利用CouchDB的优势,即基于内容的JSON查询,您的数据必须以JSON格式建模。在设置网络之前,您必须决定是使用LevelDB还是CouchDB。由于数据兼容性问题,不支持将对等体从使用LevelDB切换到CouchDB。网络上的所有对等方必须使用相同的数据库类型。如果混合使用JSON和二进制数据值,仍可以使用CouchDB,但只能根据键,键范围和组合键查询查询二进制值。

在Hyperledger Fabric中启用CouchDB

CouchDB作为独立的数据库进程与对等方一起运行,因此在设置,管理和操作方面还有其他注意事项。 可以使用CouchDB的docker镜像,我们建议它在与同级服务器相同的服务器上运行。您需要为每个对等设置一个CouchDB容器,并通过更改找到的配置core.yaml来更新每个对等容器 以指向CouchDB容器。该core.yaml 文件必须位于环境变量FABRIC_CFG_PATH指定的目录中:

  • 对于docker部署,core.yaml已预先配置并位于对等容器FABRIC_CFG_PATH文件夹中。但是,在使用docker环境时,通常通过编辑docker-compose-couch.yaml 来覆盖core.yaml 来传递环境变量

  • 对于本机二进制部署,core.yaml包含在发布工件分发中。

编辑stateDatabase部分core.yaml。指定CouchDB的 stateDatabase,并在填写相关couchDBConfig性。有关配置CouchDB以使用结构的更多详细信息,请参阅此处。以查看配置用于CouchDB的一个core.yaml文件的一个例子,检查BYFN docker-compose-couch.yamlHyperLedger/fabric-samples/first-network 目录中。

创建索引

为什么索引很重要?

索引允许查询数据库,而不必检查每个查询的每一行,使它们运行得更快,更有效。通常,索引是针对频繁出现的查询条件构建的,允许更有效地查询数据。要利用CouchDB的主要优势 - 能够针对JSON数据执行丰富查询 - 不需要索引,但强烈建议使用它们来提高性能。此外,如果查询中需要排序,CouchDB需要排序字段的索引。

没有索引的富查询将起作用,但可能会在CouchDB日志中发出未找到索引的警告。但是,如果富查询包含排序规范,则需要该字段的索引; 否则,查询将失败并将引发错误。

为了演示构建索引,我们将使用Marbles示例中的数据。在此示例中,Marbles数据结构定义为:

type marble struct {
ObjectType string `json:"docType"` //docType is used to distinguish the various types of objects in state database
Name string `json:"name"` //the field tags are needed to keep case from bouncing around
Color string `json:"color"`
Size int `json:"size"`
Owner string `json:"owner"`
}

在此结构中,属性(docTypenamecolorsize, owner)定义与资产相关联的分类账数据。该属性 docType是链代码中使用的模式,用于区分可能需要单独查询的不同数据类型。使用CouchDB时,建议包含此docType属性以区分chaincode命名空间中的每种类型的文档。(每个链代码都表示为自己的CouchDB数据库,也就是说,每个链代码都有自己的密钥命名空间。)

关于Marbles数据结构,docType用于标识此文档/资产是大理石资产。可能在链代码数据库中可能存在其他文档/资产。数据库中的文档可以针对所有这些属性值进行搜索。

在定义用于链代码查询的索引时,每个索引必须在其自己的文本文件中定义,扩展名为* .json,索引定义必须以CouchDB索引JSON格式进行格式化。

要定义索引,需要三条信息:

  • 字段:这些是经常查询的字段

  • name:索引的名称

  • type:在这种情况下总是json

例如,为名为foo-index的字段命名的简单索引foo

{
"index": {
"fields": ["foo"]
},
"name" : "foo-index",
"type" : "json"
}

可选地,ddoc可以在索引定义上指定设计文档属性。一个设计文档是CouchDB的结构设计,包含索引。索引可以分组到设计文档中以提高效率,但CouchDB建议每个设计文档使用一个索引。

定义索引时,最好将ddoc 属性和值与索引名称一起包含在内。包含此属性非常重要,以确保您可以在以后需要时更新索引。此外,它还使您能够显式指定要在查询上使用的索引。

以下是Marbles示例中索引定义的另一个示例,索引名称indexOwner使用多个字段docTypeowner 并且包含以下ddoc属性:

{
"index":{
"fields":["docType","owner"] // Names of the fields to be queried
},
"ddoc":"indexOwnerDoc", // (optional) Name of the design document in which the index will be created.
"name":"indexOwner",
"type":"json"
}

在上面的示例中,如果设计文档indexOwnerDoc尚不存在,则在部署索引时会自动创建该文档。可以使用字段列表中指定的一个或多个属性构造索引,并且可以指定任何属性组合。对于同一docType,属性可以存在于多个索引中。在以下示例中,index1 仅包括属性ownerindex2包括属性 并包含属性。另外,请注意每个索引定义都有自己的值,遵循CouchDB建议的做法。owner and colorindex3owner, color and sizeddoc

{
"index":{
"fields":["owner"] // Names of the fields to be queried
},
"ddoc":"index1Doc", // (optional) Name of the design document in which the index will be created.
"name":"index1",
"type":"json"
}

{
"index":{
"fields":["owner", "color"] // Names of the fields to be queried
},
"ddoc":"index2Doc", // (optional) Name of the design document in which the index will be created.
"name":"index2",
"type":"json"
}

{
"index":{
"fields":["owner", "color", "size"] // Names of the fields to be queried
},
"ddoc":"index3Doc", // (optional) Name of the design document in which the index will be created.
"name":"index3",
"type":"json"
}

通常,您应该为索引字段建模以匹配将在查询过滤器和排序中使用的字段。有关以JSON格式构建索引的更多详细信息,请参阅CouchDB文档。

关于索引的最后一句话,Fabric负责使用名为的模式索引数据库中的文档。在下一个查询之前,CouchDB通常不会索引新文档或更新的文档。Fabric通过在提交每个数据块之后请求索引更新来确保索引保持“温暖”。这可以确保查询很快,因为它们在运行查询之前不必索引文档。每次将新记录添加到状态数据库时,此过程都会使索引保持最新并刷新。index warming

将索引添加到您的chaincode文件夹

完成索引后,可以将其与您的链代码打包在一起,以便将其放在适当的元数据文件夹中。

如果您的链代码安装和实例化使用Hyperledger Fabric Node SDK,则JSON索引文件可以位于任何文件夹中,只要它符合此目录结构即可。在使用client.installChaincode()API 进行链代码安装期间,请metadataPath在安装请求中包含attribute()。metadataPath的值是一个字符串,表示包含JSON索引文件的目录结构的绝对路径。

或者,如果使用 peer命令安装和实例化链代码,则JSON索引文件必须位于META-INF/statedb/couchdb/indexes 链代码所在目录内的路径下。

下面的Marbles示例 说明了索引如何与将使用peer命令安装的chaincode打包在一起。

fd7c7cf6c713a4e34a96ed515e9415ff.png

此示例包含一个名为indexOwnerDoc的索引:

{"index":{"fields":["docType","owner"]},"ddoc":"indexOwnerDoc", "name":"indexOwner","type":"json"}

启动网络

需要使用Fabric Samples的1.4版本运行以下教程 。如果您已经下载了Fabric Samples 2.0版,则可以使用git checkout下载release-1.4。导航到本地计算机上的 fabric-samples目录。然后运行命令 git checkout v1.4.0

亲自尝试一下

在安装和实例化大理石链码之前,我们需要启动BYFN网络。为了本教程的目的,我们希望从已知的初始状态进行操作。以下命令将终止所有活动或过时的docker容器并删除以前生成的工件。因此,让我们运行以下命令来清理以前的任何环境:

cd fabric-samples/first-network
./byfn.sh down

现在通过运行以下命令启动与CouchDB的BYFN网络:

./byfn.sh up -c mychannel -s couchdb

这将创建一个简单的Fabric网络,其中包含一个名为mychannel的通道, 其中包含两个组织(每个组织维护两个对等节点)和一个订购服务,同时使用CouchDB作为状态数据库。

安装并实例化Chaincode

客户端应用程序通过链代码与区块链分类帐进行交互。因此,我们需要在每个将执行和支持我们的事务的对等体上安装链代码,并在通道上实例化链代码。在上一节中,我们演示了如何打包链代码,以便它们可以为部署做好准备。

Chaincode安装在对等体上,然后使用对等体实例化到通道上 。

  1. peer chaincode install命令用来在对等体上安装 Marbles链代码。

假设您已启动BYFN网络,请使用以下命令导航到CLI容器:

docker exec -it cli bash
使用以下命令将Git存储库中的Marbles链代码安装到BYFN网络中的对等方。CLI容器默认使用org1的peer0:

peer chaincode install -n marbles -v 1.0 -p github.com/hyperledger/fabric-samples/chaincode/marbles02/go

2.发出peer chaincode instantiate命令以在通道上实例化链代码。

要在BYFN通道上实例化Marbles示例,请mychannel 运行以下命令:

export CHANNEL_NAME=mychannel
peer chaincode instantiate -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 -v 1.0 -c '{"Args":["init"]}' -P "OR ('Org0MSP.peer','Org1MSP.peer')"

验证索引已部署

一旦链代码安装在对等体上并在通道上实例化,索引将被部署到每个对等体的CouchDB状态数据库。您可以通过检查Docker容器中的对等日志来验证是否已成功创建CouchDB索引。

要查看对等泊坞窗容器中的日志,请打开一个新的终端窗口并运行以下命令以grep查看已创建索引的消息。

docker logs peer0.org1.example.com  2>&1 | grep "CouchDB index"
您应该看到如下所示的结果:

[couchdb] CreateIndex -> INFO 0be Created CouchDB index [indexOwner] in state database [mychannel_marbles] using design document [_design/indexOwnerDoc]

如果BYFN对等体上未安装Marbles,则peer0.org1.example.com可能需要将其替换为安装了Marbles的其他对等体的名称。

查询CouchDB状态数据库

现在索引已在JSON文件中定义并与链代码一起部署,链代码函数可以对CouchDB状态数据库执行JSON查询,因此对等命令可以调用链代码函数。

在查询上指定索引名称是可选的。如果未指定,并且已查询的字段已存在索引,则将自动使用现有索引。

使用use_index关键字在查询中明确包含索引名称是一种很好的做法。没有它,CouchDB可能会选择一个不太理想的索引。此外,CouchDB可能根本不使用索引,您可能没有意识到,在测试期间的低容量。只有在较高的卷上,您可能会发现性能较慢,因为CouchDB没有使用索引而您认为它是。

在链代码中构建查询

您可以使用链代码中的CouchDB JSON查询语言对链代码数据值执行复杂的富查询。正如我们上面所探讨的, marbles02示例链代码 包含索引,并且在函数中定义了丰富的查询 - queryMarblesqueryMarblesByOwner

  • queryMarbles -

    ad hoc富查询的示例。这是一个查询,其中(选择器)字符串可以传递给函数。此查询对于需要在运行时动态构建自己的选择器的客户端应用程序非常有用。有关选择器的更多信息,请参阅CouchDB选择器语法。

  • queryMarblesByOwner -

    参数化查询的示例,其中查询逻辑被烘焙到链代码中。在这种情况下,函数接受单个参数,即大理石所有者。然后,它使用JSON查询语法在状态数据库中查询与“marble”的docType和所有者id匹配的JSON文档。

使用peer命令运行查询

如果没有客户端应用程序来测试链码中定义的富查询,则可以使用对等命令。对等命令从docker容器内的命令行运行。我们将自定义peer chaincode query 命令以使用Marbles索引indexOwner并使用该queryMarbles函数查询“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","marble1","blue","35","tom"]}'

在链代码实例化期间部署索引之后,链代码查询将自动使用它。CouchDB可以根据要查询的字段确定要使用的索引。如果查询条件存在索引,则将使用该索引。但是,建议的方法是use_index在查询中指定关键字。下面的peer命令是一个如何通过包含use_index关键字在选择器语法中显式指定索引的示例:

// Rich Query with index name explicitly specified:
peer chaincode query -C $CHANNEL_NAME -n marbles -c '{"Args":["queryMarbles", "{\"selector\":{\"docType\":\"marble\",\"owner\":\"tom\"}, \"use_index\":[\"_design/indexOwnerDoc\", \"indexOwner\"]}"]}'

深入研究上面的查询命令,有三个感兴趣的参数:

  • queryMarbles

Marbles链码中的函数名称。请注意,垫片  shim.ChaincodeStubInterface 用于访问和修改分类帐。在  getQueryResultForQueryString() 通过查询字符串的垫片API  getQueryResult()
func (t *SimpleChaincode) queryMarbles(stub shim.ChaincodeStubInterface, args []string) pb.Response {

// 0
// "queryString"
if len(args) < 1 {
return shim.Error("Incorrect number of arguments. Expecting 1")
}

queryString := args[0]

queryResults, err := getQueryResultForQueryString(stub, queryString)
if err != nil {
return shim.Error(err.Error())
}
return shim.Success(queryResults)
}
  • {"selector":{"docType":"marble","owner":"tom"}

这是一个示例 特设选择 其中发现类型的所有文件的字符串 marble ,其中 owner 属性具有值 tom
  • "use_index":["_design/indexOwnerDoc", "indexOwner"]

指定设计文档名称  indexOwnerDoc 和索引名称  indexOwner 。在此示例中,选择器查询显式包含使用 use_index 关键字指定的索引名称。回顾上面的索引定义创建一个索引 ,它包含一个设计文档,  "ddoc":"indexOwnerDoc" 。对于CouchDB,如果计划在查询中明确包含索引名称,则索引定义必须包含该  ddoc 值,因此可以使用 use_index 关键字引用它。

查询成功运行,并利用以下结果利用索引:

Query Result: [{"Key":"marble1", "Record":{"color":"blue","docType":"marble","name":"marble1","owner":"tom","size":35}}]

使用查询和索引的最佳实践

使用索引的查询将更快完成,而无需扫描couchDB中的完整数据库。了解索引将允许您编写查询以获得更好的性能,并帮助您的应用程序处理网络上的大量数据或块。

规划使用链代码安装的索引也很重要。您应该只为每个支持大多数查询的链代码安装几个索引。添加过多索引或在索引中使用过多字段会降低网络性能。这是因为在提交每个块之后会更新索引。需要通过“索引升温”更新索引越多,交易完成所需的时间就越长。

本节中的示例将帮助演示查询如何使用索引以及哪种类型的查询将具有最佳性能。在编写查询时请记住以下内容:

  • 索引中的所有字段也必须位于查询的选择器或排序部分,以便使用索引。

  • 更复杂的查询将具有较低的性能,并且不太可能使用索引。

  • 你应该尽量避免运营商,这将导致全表扫描或全索引扫描,如$or$in$regex

在本教程的上一部分中,您针对弹珠链代码发出了以下查询:

// Example one: query fully supported by the index
peer chaincode query -C $CHANNEL_NAME -n marbles -c '{"Args":["queryMarbles", "{\"selector\":{\"docType\":\"marble\",\"owner\":\"tom\"}, \"use_index\":[\"indexOwnerDoc\", \"indexOwner\"]}"]}'

大理石链码与indexOwnerDoc索引一起安装:

{"index":{"fields":["docType","owner"]},"ddoc":"indexOwnerDoc", "name":"indexOwner","type":"json"}

请注意,无论是在查询的字段,docType并且owner都包含在索引中,使其成为一个完全支持查询。因此,此查询将能够使用索引中的数据,而无需搜索完整数据库。完全支持的查询(例如此查询)将比链代码中的其他查询返回得更快。

如果您向上面的查询添加额外的字段,它仍将使用索引。但是,查询还必须扫描额外字段的索引数据,从而导致更长的响应时间。例如,下面的查询仍将使用索引,但返回的时间比前一个示例要长。

// Example two: query fully supported by the index with additional data
peer chaincode query -C $CHANNEL_NAME -n marbles -c '{"Args":["queryMarbles", "{\"selector\":{\"docType\":\"marble\",\"owner\":\"tom\",\"color\":\"red\"}, \"use_index\":[\"/indexOwnerDoc\", \"indexOwner\"]}"]}'

不包含索引中所有字段的查询将必须扫描整个数据库。例如,下面的查询搜索所有者,而不指定所拥有项的类型。由于ownerIndexDoc包含ownerdocType字段,因此该查询将无法使用索引。

// Example three: query not supported by the index
peer chaincode query -C $CHANNEL_NAME -n marbles -c '{"Args":["queryMarbles", "{\"selector\":{\"owner\":\"tom\"}, \"use_index\":[\"indexOwnerDoc\", \"indexOwner\"]}"]}'

通常,更复杂的查询将具有更长的响应时间,并且索引支持的可能性更低。运营商如$or$in$regex往往会导致查询扫描完整的索引或不会使用索引的。

例如,下面的查询包含一个$or术语,用于搜索tom拥有的每个大理石和每个项目。

// Example four: query with $or supported by the index
peer chaincode query -C $CHANNEL_NAME -n marbles -c '{"Args":["queryMarbles", "{\"selector\":{"\$or\":[{\"docType\:\"marble\"},{\"owner\":\"tom\"}]}, \"use_index\":[\"indexOwnerDoc\", \"indexOwner\"]}"]}'

此查询仍将使用索引,因为它会搜索包含在其中的字段indexOwnerDoc。但是,$or查询中的条件需要扫描索引中的所有项目,从而导致响应时间更长。

下面是索引不支持的复杂查询的示例。

// Example five: Query with $or not supported by the index
peer chaincode query -C $CHANNEL_NAME -n marbles -c '{"Args":["queryMarbles", "{\"selector\":{"\$or\":[{\"docType\":\"marble\",\"owner\":\"tom\"},{"\color\":"\yellow\"}]}, \"use_index\":[\"indexOwnerDoc\", \"indexOwner\"]}"]}'

该查询搜索由汤姆拥有的所有大理石或任何其他黄色项目。此查询将不使用索引,因为它将需要搜索整个表以满足$or条件。根据分类帐上的数据量,此查询将花费很长时间来响应或可能会超时。

虽然遵循查询的最佳实践很重要,但使用索引并不是收集大量数据的解决方案。区块链数据结构经过优化,可以验证和确认交易,不适合数据分析或报告。如果要将仪表板构建为应用程序的一部分或分析网络中的数据,最佳做法是查询从同行复制数据的离线数据库。这样您就可以了解区块链上的数据,而不会降低网络性能或中断事务。

您可以使用应用程序中的块或链代码事件将事务数据写入脱链数据库或分析引擎。对于收到的每个块,块监听器应用程序将遍历块事务并使用每个有效事务的键/值写入构建数据存储rwset。基于 Peer通道的事件服务提供可重放事件,以确保下游数据存储的完整性。

使用分页查询CouchDB状态数据库

当CouchDB查询返回大型结果集时,可以使用一组API,这些API可以通过链代码调用以对结果列表进行分页。分页提供了一种通过指定a pagesize和起始点来分区结果集的机制- bookmark指示从哪里开始结果集。客户端应用程序迭代地调用执行查询的链代码,直到不再返回结果。有关更多信息,请参阅有关CouchDB分页的此主题。

我们将使用 Marbles示例 函数queryMarblesWithPagination来演示如何在链代码和客户端应用程序中实现分页。

  • queryMarblesWithPagination -

    具有分页的临时丰富查询的示例。这是一个查询,其中(选择器)字符串可以传递到类似于上面示例的函数中。在这种情况下,a pageSize也包含在查询中以及a中bookmark

为了展示分页,需要更多数据。此示例假定您已从上方添加了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还添加了pagesizebookmarkPageSize 指定每个查询返回的记录数。这bookmark是一个“锚”告诉couchDB在哪里开始页面。(每个结果页面都会返回一个唯一的书签。)

  • queryMarblesWithPagination

Marbles链码中的函数名称。请注意,垫片  shim.ChaincodeStubInterface 用于访问和修改分类帐。在  getQueryResultForQueryStringWithPagination() 与页面大小和书签垫片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命令,它使用pageSize调用queryMarblesWithPagination 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调用queryMarblesWithPagination的peer命令3。请注意,这次查询包括从上一个查询返回的书签。

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"}}]

有关客户端应用程序如何使用分页迭代结果集getQueryResultForQueryStringWithPagination 的示例,请在Marbles示例中搜索该函数。

更新索引

可能需要随时间更新索引。安装的链代码的后续版本中可能存在相同的索引。为了更新索引,原始索引定义必须包含设计文档ddoc属性和索引名称。要更新索引定义,请使用相同的索引名称,但更改索引定义。只需编辑索引JSON文件,然后在索引中添加或删除字段。Fabric仅支持索引类型JSON,不支持更改索引类型。安装并实例化链代码后,更新的索引定义将重新部署到对等方的状态数据库。对索引名称或ddoc属性的更改将导致创建新索引,并且原始索引在CouchDB中保持不变,直到将其删除。

如果状态数据库具有大量数据,则需要一些时间来重建索引,在此期间链代码调用问题查询可能会失败或超时。

迭代索引定义

如果您可以在开发环境中访问对等的CouchDB状态数据库,则可以迭代测试各种索引以支持您的链代码查询。但是对链码的任何更改都需要重新部署。使用CouchDB Fauxton接口或命令行curl实用程序来创建和更新索引。

Fauxton接口是用于创建,更新和部署CouchDB索引的Web UI。如果你想试试这个界面,有一个Marbles样本中索引的Fauxton版本格式的例子。如果您已使用CouchDB部署BYFN网络,则可以通过打开浏览器并导航到加载Fauxton界面http://localhost:5984/_utils

或者,如果您不想使用Fauxton UI,则以下是curl命令的示例,该命令可用于在数据库上创建索引mychannel_marbles

// docType的索引,所有者。//示例curl命令行,用于在CouchDB channel_chaincode数据库中定义索引

curl -i -X POST -H "Content-Type: application/json" -d
"{\"index\":{\"fields\":[\"docType\",\"owner\"]},
\"name\":\"indexOwner\",
\"ddoc\":\"indexOwnerDoc\",
\"type\":\"json\"}" http://hostname:port/mychannel_marbles/_index

如果您使用的是使用CouchDB配置的BYFN,请将hostname:port替换为localhost:5984

删除索引

索引删除不受Fabric工具管理。如果需要删除索引,请手动对数据库发出curl命令或使用Fauxton接口将其删除。

删除索引的curl命令的格式为:

curl -X DELETE http://localhost:5984/{database_name}/_index/{design_doc}/json/{index_name} -H  "accept: */*" -H  "Host: localhost:5984"

要删除本教程中使用的索引,curl命令将是:

curl -X DELETE http://localhost:5984/mychannel_marbles/_index/indexOwnerDoc/json/indexOwner -H "accept: */*" -H "Host: localhost:5984"
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值