胡豆秆

个人博客

欢迎来到我的个人博客~


CouchDB


CouchDB

​ Apache CouchDB 是一个面向文档的数据库管理系统。它提供以 JSON 作为数据格式的 REST 接口来对其进行操作,并可以通过视图来操纵文档的组织和呈现。 CouchDB 是 Apache 基金会的顶级开源项目。

介绍

​ couchDB的字段只有三个:文档ID、文档版本号和内容。内容字段可以看到是一个text类型的文本,里面可以随意定义数据,而不用关注数据类型,但数据必须以json的形式表示并存放。例如一个表述用户的文档可以表示为:[_id:1001, _rev:1-32443289, {‘name’:’wentrue’, ‘location’:’beijing’}]。couchDB把所有的属性忽略schema都统一放在一个字段里,那么当有两个程序同时修改这个字段时,就有可能造成先写入的数据被后写入的数据覆盖的现象,导致数据不一致。couchDB利用版本号来解决这个问题,当有程序需要修改一条数据时,它必须先把这个数据的版本号读出来,写入的时候,连版本号一并写入,此时couchDB会检查该版本号是否与原数据的一致,如果一致则写入,如果不一致,则说明数据在该程序读出后已经被修改过,couchDB会写入不成功,返回一个冲突的信号,待客户端程序处理。

​ couchDB的底层是erlang语言,以RESTful API的格式提供服务,couchDB所有的读写能力都可以通过简单的调用它的HTTP请求来实现。正因为采用那么一种统一且简洁的服务接口,可以很方便地开发各种语言的客户端,以方便不同程序员的使用。

​ couchDB的主要特点在于易用性及并发性。couchDB的底层是一个B-tree的存储结构,为提高效率,所有的数据的插入或更新都是直接在树的叶子节点添加,不删除旧节点,通过版本号来确定最新的数据--版本号还能用来解决并发写的冲突。所以数据文件会越来越大,可以在适当地时间运行compact过程或replication过程,会删除旧文件,使得数据文件得到压缩。

​ couchDB的属性可以灵活增删,要增加一个新属性只需要往数据字段多写入一个属性即可。couchDB以json格式存储数据,返回的数据也默认为json格式,这对于前端的javascript处理是非常方便的。

区块链中的使用

​ 在Fabric链码中,不管是通过 GetState()GetPrivateDataGetStateByPartialCompositeKey 等来从账本中获取数据时,它们都是通过账本数据的 Key 来确定数据。在某些场景下,可能会需要通过账本数据中的 Value 值来筛选数据(如获取性别为男的所有数据)。当然,使用组合键也能达到这种需求,但组合键的创建和存储都比较麻烦(需要所有的组合键都需要被创建和存储到账本数据中,本质上组合键也是通过Key来筛选数据)。

富查询

​ 为了能够简单的通过Value值来筛选数据,在链码中可以使用CouchDB的富查询功能。 shim.ChaincodeStubInterface 实例所提供的的 GetQueryResult 方法可实现富查询功能。该方法需传入一个Json对象,key 为 selector ,value为待筛选的属性值。如 {"selector":{"sex":"男"},{"province":"浙江"}}

func GetCommodityByName(stub shim.ChaincodeStubInterface, args []string) pb.Response {
	//todo
	if len(args) != 1 {
		return shim.Error("参数非法!参数顺序:name")
	}
    // `{"selector":{"属性名":"属性值"}}`
	query := fmt.Sprintf(`{"selector":{"name":"%v"}}`,args[0])
	var commodities []Commodity
	iterator,_ := stub.GetQueryResult(query)
	defer iterator.Close()
	for iterator.HasNext() {
		kv,_ := iterator.Next()
		var commodity Commodity
		_ = json.Unmarshal(kv.Value,&commodity)
		fmt.Println(commodity)
		commodities = append(commodities,commodity)
	}
	data,_ := json.Marshal(commodities)
	return shim.Success(data)
}

索引

​ 智能合约代码中业务如果涉及到couchdb的富查询,例如根据供应商去查询一些相关的信息,如果没有建立索引的话,在查询中会慢的很痛苦,而且数据量大的情况下会出现莫名的error。

​ couchDB的索引创建很简单,只需在链码的同级目录下建立文件夹META-INF/statedb/couchdb/indexes/,并添加一个json文件:

{
  "index": {
    "fields": [
      "属性名"
    ]
  },
  "ddoc": "自定义名称",
  "name": "自定义名称",
  "type": "json"
}

Fabric-samples项目中的链码包 marbles02 所使用的索引文件为:

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

查询格式

CouchDB的查询语句是一个JSON格式的字符串,示例如下:

{
    "selector": {
        "year": {"$gt": 2010}
    },
    "fields": ["_id", "_rev", "year", "title"],
    "sort": [{"year": "asc"}],
    "limit": 2,
    "skip": 0,
    "execution_stats": true
}
  • selector - 选择器 参数为Json格式的数据筛选条件,类似于SQL中的 WHERE 必填
  • limit - 条数 参数为整数,查询返回的最大条数 可选
  • skip - 跳过 参数为整数,跳过前面的指定条 可选
  • sort - 排序 参数为JSON数组,结果排序 可选
  • fields - 过滤 参数为数组,过滤掉指定字段 可选

更多CouchDB查询资料可查看 CouchDB 官网文档

选择器

组合字符列表:

  • $and - 数组参数

    { $and: [ { <表达式1> },{ <表达式2> }, ... ] } 同时满足数组中的所有表达式

  • $or - 数组参数

    { $or: [ { <表达式1> }, { <表达式2> }, ... ] } 满足数组中任意表达式

  • $not - 单一参数

    { $not: [ { <表达式1> }, { <表达式2> }, ... } ] } 不满足数组中的任意表达式

  • $nor - 数组参数

    { $nor: [ { <表达式1> }, { <表达式2> }, ... } ] } 同时不满足数组中的全部表达式

  • $all - 数组参数(操作对象为数组)

    { <字段名>: { $all: [ <值1>, <值2>, ... ] } } 选择对象应该为数组字段,数据中的该数组字段包含所有数组中的表达式。匹配非数组类型的字段时与 $eq 一致

  • $elemMatch - 单一参数(操作对象为数组)

    { <字段名>: { $elemMatch: { <子字段名>: <表达式>, ... } } } 选择对象应该为数组字段,字段中至少有一条数据包含了数组中的表达式。

条件参数列表

平等运算符

  • $lt - 任意JSON

    { <字段名>: { $lt: <值> } } 字段小于给定值时 less than

  • $lte - 任意JSON

    { <字段名>: { $lte: <值> } } 字段小于等于给定值时 less than equal

  • $eq - 任意JSON

    { <字段名>: { $eq: <值> } } 字段等于给定值时 equal

  • $ne - 任意JSON

    { <字段名>: { $ne: <值> } } 字段小于给定值时 not equal

  • $gte - 任意JSON

    { <字段名>: { $lt: <值> } } 字段大于等于给定值时 greater than equal

  • $gt - 任意JSON

    { <字段名>: { $lt: <值> } } 字段大于给定值时 greater than

对象相关运算符

  • $exists - Boolean

    { <字段名>: { $exists: <值> } } 字段是否存在

  • $type - 字符串

    { <字段名>: { $type: <值> } } 字段类型 null, boolean , number , array , object , string

数组相关运算符

  • $in - JSON数组(操作对象为数组)

    { <字段名>: { $in: [ { <值1> },{ <值2> }, ... ] } } 数组字段中包含了某一个给定值

  • $nin - JSON数组(操作对象为数组)

  • $nin - JSON数组

    { <字段名>: { $nin: [ { <值1> },{ <值2> }, ... ] } } 数组字段中不包含某一个给定值

  • $size - 整数(操作对象为数组)

    { <字段名>: { $size: <值> } } 数组长度等于给定值

其它运算符

  • $mod - [Divisor, Remainder] (操作对象只能是整数)

  • { <字段名>: { $mod: [ Divisor,Remainder] } } 字段 % Divisor == Remainder

  • $regex - 字符串

    { <字段名>: { $regex: <正则表达式> } } 字段值匹配正则表达式

打赏一个呗

取消

感谢您的支持,我会继续努力的!

扫码支持
扫码支持
扫码打赏,你说多少就多少

打开支付宝扫一扫,即可进行扫码打赏哦