couchdb 安装/使用
需求: 要对数据库中的记录做版本管理.
通过调查, 排除了es
,mongodb
,couchBase
,ravendb
最终选用了couchdb
.
之所以选用couchdb
, 是因为 couchdb 是支持对文档所版本管理. 而且默认查询可以使获取最新版本记录.
es
的 version 仅做记录用, 旧版本的数据不可查, 并且会在特定的时间被删除掉. 比如内存或者硬盘不足的时候.
mongo
做版本管理查询过于麻烦. 或者每次更新都需要把上一个版本的状态改为 false. (其余关系型数据类似)
couchBase
的 version 同样只用于做版本冲突用. 没有办法回溯历史记录
另外,ravendb
是可以满足需求的, 但项目需求 couchdb 可以满足. 主要原因我看了 ravendb-python-client 文档, 翻了源码, 没有对 version 的相关接口进行封装.ravendb
本身是支持 version 的, python SDK 不支持. 使用@metadata.@change-vector
做为版本号key. (这里不多介绍, 下篇文章再做介绍)
Couchdb Github: https://github.com/apache/couchdb
Couchdb-python Github: https://github.com/djc/couchdb-python
下载/安装
Macbook 上用 brew 安装
$ brew install couchdb
$ brew services start couchdb
一直启动不成功, 实在找不到问题所在, 也没有任何 Log. 不用 brew 启动, 找到安装目录, 直接启动的时候可以看到有 log 输出.
$ /usr/local/Cellar/couchdb/1.7.1_4/bin/couchdb
$ cat /Users/zhipeng/Library/Logs/CouchDB2.log
{"init terminating in do_boot",{{badmatch,{error,{bad_return,{{couch_app,start,[normal,["/usr/local/etc/couchdb/default.ini","/usr/local/etc/couchdb/local.ini"]]},{'EXIT',{{badmatch,{error,{error,enoent}}},[{couch_server_sup,start_server,1,[{file,"couch_server_sup.erl"},{line,56}]},{application_master,start_it_old,4,[{file,"application_master.erl"},{line,273}]}]}}}}}},[{couch,start,0,[{file,"couch.erl"},{line,18}]},{init,start_em,1,[]},{init,do_boot,3,[]}]}}
brew 安装后不会创建默认的 default.ini 和 local.ini, 有可能是这个导致的.没有做测试, 因为我最后用源码安装的.
Macbook 可以下载封装好的 app, 可以直接运行
下载地址: https://dl.bintray.com/apache/couchdb/mac/2.1.1/Apache-CouchDB-2.1.1-1.zip
$ wget https://dl.bintray.com/apache/couchdb/mac/2.1.1/Apache-CouchDB-2.1.1-1.zip
$ unzip Apache-CouchDB-2.1.1-1.zip
$ open Apache CouchDB.app
使用源码安装
下载页面: https://www.apache.org/dyn/closer.lua?path=/couchdb/source/2.1.1/apache-couchdb-2.1.1.tar.gz
$ wget http://mirrors.hust.edu.cn/apache/couchdb/source/2.1.1/apache-couchdb-2.1.1.tar.gz
$ tar zxvf apache-couchdb-2.1.1.tar.gz && cd apache-couchdb-2.1.1
$ ./confugure
$ make release
$ cd rel/couchdb
$ ./bin/couchdb
# sudo cp -r rel/couchdb /usr/local/
# echo "PATH=/usr/local/couchdb/bin/:$PATH"
测试是否启动
可以看到启动成功. 默认端口是5984
$ curl localhost:5984
{"couchdb":"Welcome","version":"2.1.1","features":["scheduler"],"vendor":{"name":"The Apache Software Foundation"}}
也可以用浏览器打开 http://localhost:5984/_utils/, 可以看到网页版本的数据库管理页面
详细的服务配置可以进入: http://localhost:5984/_utils/#/_config 进行查看
我试过在这里直接修改配置, 没有生效. 所以如果想修改配置还是在 rel/couchdb/etc/local.ini 中添加修改.
但是控制台一直在报错 Error in process ... database_does_not_exist .. load_shards_from_db _users
[error] 2018-04-04T04:46:25.209913Z couchdb@127.0.0.1 emulator -------- Error in process <0.334.0> on node 'couchdb@127.0.0.1' with exit value:
{database_does_not_exist,[{mem3_shards,load_shards_from_db,"_users",[{file,"src/mem3_shards.erl"},{line,403}]},{mem3_shards,load_shards_from_disk,1,[{file,"src/mem3_shards.erl"},{line,378}]},{mem3_shards,load_shards_from_disk,2,[{file,"src/mem3_shards.erl"},{line,407}]},{mem3_shards,for_docid,3,[{file,"src/mem3_shards.erl"},{line,91}]},{fabric_doc_open,go,3,[{file,"src/fabric_doc_open.erl"},{line,38}]},{chttpd_auth_cache,ensure_auth_ddoc_exists,2,[{file,"src/chttpd_auth_cache.erl"},{line,187}]},{chttpd_auth_cache,listen_for_changes,1,[{file,"src/chttpd_auth_cache.erl"},{line,134}]}]}
这个错误是因为缺少 _users 这张数据库, 不明思意, 就是一个权限管理的库. 添加 _users
数据库即可解决这个问题.
测试
测试可以使用浏览器直接测试, 这里不做说明
使用 curl 测试
创建 DB
$ curl -X PUT http://localhost:5984/test_users
{"ok":true}
$ curl -X PUT http://localhost:5984/test_users
{"error":"file_exists","reason":"The database could not be created, the file already exists."}
生成 UUID
curl http://localhost:5984/_uuids?count=1
curl http://localhost:5984/_uuids
{
"uuids": [
"21b82b342ae7a4b069cda0b21c001748"
]
}
添加一条记录 (_id 可以自己定义, 也可以使用生成的 UUID)
$ curl -XPUT http://localhost:5984/test_users/zhipeng -d '{"_id":"zhipeng","age":20,"st":1500000000,"info":{"a":123,"b":456},"desc":"入口并不算太显眼....."}'
{"ok":true,"id":"zhipeng","rev":"1-6b069050a23af3a9bb4fb5af59a99a5f"}
// 原始文本是这样的, 我测试了一下中文和换行
{
"_id": "zhipeng",
"age": 20,
"st": 1500000000,
"info": {
"a": 123,
"b": 456
},
"desc": "入口并不算太显眼,进去别有洞天。健身餐吧、游泳池、篮球场、超大瑜伽房等一应俱全,力健、必确、班霸等各类高端有氧器械共60台左右;固定器械不胜枚举,连悍马的reverse hyper都配了;自由重量上片足够,架子是悍马的,地板特殊处理过,随便摔杠。接待我的销售小哥彬彬有礼,谈吐形象俱佳,在常规健身会所基本就是个店长的材料。6月试营业,部分设施还在调整中(比如楼顶的泳池我就没去参观),报价年卡16000元。我估摸老板的来历不小,可能不是一般的有钱啊。预计将来这个馆子会成为北京三里屯一个新的健身、娱乐、社交等相结合的新去处(我似乎看到一大票女主播、网红、富二代正赶来)。反正根据我的认知,这是全国最土豪的健身中心。\n作者:谢奕炜\n链接:https://www.ztest_usershu.com/question/26942323/answer/191704563\n来源:知乎\n著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。"
}
查询 - 获取所有记录(只获取 id 和 rev)
$ curl http://localhost:5984/test_users/_all_docs?limit=30
{
"total_rows": 1,
"offset": 0,
"rows": [
{
"id": "zhipeng",
"key": "zhipeng",
"value": {
"rev": "1-6b069050a23af3a9bb4fb5af59a99a5f"
}
}
]
}
查询 - 根据 _id 查询
$ curl http://localhost:5984/test_users/zhipeng
{
"_id": "zhipeng",
"_rev": "1-6b069050a23af3a9bb4fb5af59a99a5f",
"age": 20,
"st": 1500000000,
"info": {
"a": 123,
"b": 456
},
"desc": "入口并不算太显眼,进去别有洞天。健身餐吧、游泳池、篮球场、超大瑜伽房等一应俱全,力健、必确、班霸等各类高端有氧器械共60台左右;固定器械不胜枚举,连悍马的reverse hyper都配了;自由重量上片足够,架子是悍马的,地板特殊处理过,随便摔杠。接待我的销售小哥彬彬有礼,谈吐形象俱佳,在常规健身会所基本就是个店长的材料。6月试营业,部分设施还在调整中(比如楼顶的泳池我就没去参观),报价年卡16000元。我估摸老板的来历不小,可能不是一般的有钱啊。预计将来这个馆子会成为北京三里屯一个新的健身、娱乐、社交等相结合的新去处(我似乎看到一大票女主播、网红、富二代正赶来)。反正根据我的认知,这是全国最土豪的健身中心。\n作者:谢奕炜\n链接:https://www.zhihu.com/question/26942323/answer/191704563\n来源:知乎\n著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。"
}
查询 - 查询语法
$ curl -H "Content-Type: application/json" -X POST http://localhost:5984/test_users/_find --data '{"selector":{"_id":"zhipeng"},"limit":21,"skip":0}'
{
"docs": [
{
"_id": "zhipeng",
"_rev": "1-6b069050a23af3a9bb4fb5af59a99a5f",
"age": 20,
"st": 1500000000,
"info": {
"a": 123,
"b": 456
},
"desc": "入口并不算太显眼,进去别有洞天。健身餐吧、游泳池、篮球场、超大瑜伽房等一应俱全,力健、必确、班霸等各类高端有氧器械共60台左右;固定器械不胜枚举,连悍马的reverse hyper都配了;自由重量上片足够,架子是悍马的,地板特殊处理过,随便摔杠。接待我的销售小哥彬彬有礼,谈吐形象俱佳,在常规健身会所基本就是个店长的材料。6月试营业,部分设施还在调整中(比如楼顶的泳池我就没去参观),报价年卡16000元。我估摸老板的来历不小,可能不是一般的有钱啊。预计将来这个馆子会成为北京三里屯一个新的健身、娱乐、社交等相结合的新去处(我似乎看到一大票女主播、网红、富二代正赶来)。反正根据我的认知,这是全国最土豪的健身中心。\n作者:谢奕炜\n链接:https://www.zhihu.com/question/26942323/answer/191704563\n来源:知乎\n著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。"
}
],
"bookmark": "g1AAAAA-eJzLYWBgYMpgSmHgKy5JLCrJTq2MT8lPzkzJBYqzV2VkFqTmpYOkOWDSyBJZACZ3Eq0",
"warning": "no matching index found, create an index to optimize query time"
}
// 还支持一些别的查询语法, 还支持 json 查询.
//
{
"selector": {
"info.b": 456,
"age": {
"$lt": 22
}
}
}
// 查询某个字段一定存在的
{
"selector": {
"girl_friend_name": {
"$ne": null
}
}
}
更新
$ curl -X PUT "http://localhost:5984/test_users/z?conflicts=true" -d '{"age":21,"st":1500000000,"info":{"a":1233,"b":456},"desc":"入口并不算太显眼.....","t":"test update."} '
{"error":"conflict","reason":"Document update conflict."}
# 可以看到这里报错, 说文档冲突
curl -X PUT "http://localhost:5984/test_users/z?conflicts=true" -d '{"_id":"z","_rev":"5-3b0a0a3813849918f87b2af9ce3e1ad5","age":21,"st":1500000000,"info":{"a":1233,"b":456},"desc":"入口并不算太显眼.....","t":"test update."}
'
更新的时候, 必须指定
_rev
, 否则会冲突.
更新的时候_id
是否存在没有任何影响, 仅限PUT
. 如果用POST
, 并且没有_id
会创建一条新的记录.
删除
$ curl -X DELETE "http://localhost:5984/test_users/z?rev=8-f15c6c850b08b08119adebaa5bb3d709"
{"ok":true,"id":"z","rev":"9-8bf58a524f5f4dd35a847140744f768c"}
# 也可以使用 bulk 进行批量删除,
$ curl -H "Content-Type: application/json" -X POST http://localhost:5984/test_users/_bulk_docs -d '{"docs":[{"_id":"z","_rev":"6-fe1dd27d7c8fd08cec1ab6d48cf571c0","_deleted":true}]}'
[{"id":"c","error":"conflict","reason":"Document update conflict."}]
$ curl "http://localhost:5984/test_users/z?rev=8-f15c6c850b08b08119adebaa5bb3d709"
{"_id":"z","_rev":"8-f15c6c850b08b08119adebaa5bb3d709"}
$ curl "http://localhost:5984/test_users/z?rev=9-8bf58a524f5f4dd35a847140744f768c"
{"_id":"z","_rev":"9-8bf58a524f5f4dd35a847140744f768c","_deleted":true}
删除的时候必须指定 rev, 否则会报冲突
删除只是删除当前版本, 并且会生成出一个被删除的版本. 旧版本是可以继续查到的.
如果再创建一条记录,_id
存在过, 版本号会在最后一次删除的版本基础上 +1.
查看版本记录
$ curl http://localhost:5984/test_users/z?revs=true&&revs_info=true
{
"_id": "z",
"_rev": "10-79aba04561eab0aef960abc4df9520e8",
"desc": "recreate it",
"_revisions": {
"start": 10,
"ids": [
"79aba04561eab0aef960abc4df9520e8",
"8bf58a524f5f4dd35a847140744f768c",
"f15c6c850b08b08119adebaa5bb3d709",
"8ec0d9a8a28c15872a244df967503c82",
"fe1dd27d7c8fd08cec1ab6d48cf571c0",
"3b0a0a3813849918f87b2af9ce3e1ad5",
"fe44e13101c6382291e51f3b1318927b",
"5e9c6795de58378bb3963fce5f2a27e9",
"cfd2f60bb987d851f552c2ab3fa790da",
"9981ba3a952cefe86cea846f583b9729"
]
},
"_revs_info": [
{
"rev": "10-79aba04561eab0aef960abc4df9520e8",
"status": "available"
},
{
"rev": "9-8bf58a524f5f4dd35a847140744f768c",
"status": "deleted"
},
{
"rev": "8-f15c6c850b08b08119adebaa5bb3d709",
"status": "available"
},
{
"rev": "7-8ec0d9a8a28c15872a244df967503c82",
"status": "deleted"
},
{
"rev": "2-cfd2f60bb987d851f552c2ab3fa790da",
"status": "available"
},
{
"rev": "1-9981ba3a952cefe86cea846f583b9729",
"status": "available"
}
]
}
revs=true
可以显示所有版本号, 只显示版本号,_revisions.ids
倒叙显示, 最新记录靠前.
revs_info=true
可以显示所有版本状态
查看某个版本记录
$ curl "http://localhost:5984/test_users/z?rev=1-9981ba3a952cefe86cea846f583b9729"
{"_id":"z","_rev":"1-9981ba3a952cefe86cea846f583b9729","age":20,"st":1500000000,"info":{"a":123,"b":456},"desc":"入口并不算太显眼....."}
$ curl "http://localhost:5984/hi/z?rev=9-8bf58a524f5f4dd35a847140744f768c"
{"_id":"z","_rev":"9-8bf58a524f5f4dd35a847140744f768c","_deleted":true}
参考
InfoQ-Apache CouchDB 2.0开发者预览版发布,支持集群的水平扩展 – http://www.infoq.com/cn/news/2014/11/apache-couch-2.0-release
couchdb-Apache CouchDB 2.0 Documentation – http://docs.couchdb.org/en/2.0.0/api/document/common.html#obtaining-a-specific-revision
wikipedia-CouchDB – https://zh.wikipedia.org/wiki/CouchDB
InfoQ-CouchDB是什么?为什么我们要关注它?
stackoverflow-Unable to start CouchDB – https://stackoverflow.com/questions/14453082/unable-to-start-couchdb
初窥NoSQL世界 开源CouchDB新手入门 – http://tech.it168.com/a2011/0331/1172/000001172983_all.shtml