「7つのデータベース 7つの世界」第6章の学習のために、CouchDB(カウチ)をインストールします。
7つのデータベース 7つの世界
- PotgreSQL
- Riak
- HBase
- MongoDB
- CouchDB
- Neo4j
- Redis
原著の発行は 2012/5/21 で、書籍で使ったCouchDBのバージョンは 1.1.1 です。(p167のスクショより)
docker-composeで動かしたのは、2.3.1です。
最新バージョンは 3.1.0 です。

UbuntuではCouchDBのインストールも難しくて、結局dockerイメージを使ったよ。

書籍中のコードが動くといいわね
インストール
dockerイメージ

公式Dockerイメージ 2.3.1 を使いました。
docker-compose.yml
version: "2"
services:
mycouchdb:
image: couchdb:2.3.1
ports:
- "5984:5984"
Code language: YAML (yaml)
docker-composeで起動します。
$ sudo docker-compose up -d
Windows 10
msiファイルをダウンロードしたのですが、3回とも途中で失敗しました。

たまたまかな?
Mac OS X
zipファイル
zipファイルをダウンロードしたのですが、3回とも途中で失敗しました。

別の日に試してみたら?
Homebrew cask
3.1.0がインストールされます。
Homebrew cask のパッケージ名は「apache-couchdb」です。
$ brew cask install apache-couchdb
(省略)
==> Moving App 'Apache CouchDB.app' to '/Applications/Apache CouchDB.app'.
🍺 apache-couchdb was successfully installed!
Code language: Bash (bash)
Applicationsに「Apache CouchDB.app」としてインストールされたようです。Applicationsに「Apache CouchDB.app」を開きます。

adminパスワードを設定します。ここでは "password" にしました。

Fauxtonのログイン画面が表示されました。"admin"、"password"と入力してログインします。

Fauxton画面が表示されました!

起動したcouchdbをstopする方法はわかりませんでした。psで探して、killしました。
$ ps x | grep -i couch | grep -v grep | cut -d' ' -f2 | xargs -L1 kill
Code language: Bash (bash)
Homebrew
Homebrewでは 3.0.0がインストールされます。
Homebrew のパッケージ名は「couchdb」です。
$ brew install couchdb
(省略)
To have launchd start couchdb now and restart at login:
brew services start couchdb
Or, if you don't want/need a background service you can just run:
couchdb
Code language: Bash (bash)
「brew services start couchdb」か「couchdb」で起動できるようです。
local.iniでadminアカウントの設定をします。local.iniは、/usr/local/Cellar/couchdb/3.1.0/etc/ にありました。
$ tree /usr/local/Cellar/couchdb/3.1.0/etc/
/usr/local/Cellar/couchdb/3.1.0/etc/
├── default.d
│ └── README
├── default.ini
├── local.d
│ └── README
├── local.ini
└── vm.args
2 directories, 5 files
Code language: Bash (bash)
最後の行の「;」を削除します。ここでは平文で "password" を設定しました。
編集前
[admins]
;admin = mysecretpassword
編集後
[admins]
admin = password
Code language: Bash (bash)
まず「brew services start couchdb」を試してみます。
$ brew services start couchdb
==> Successfully started `couchdb` (label: homebrew.mxcl.couchdb)
Code language: Bash (bash)
localhost:5984/_utils にアクセスすると、ログイン画面が表示されました。いったんstopします。
$ brew services stop couchdb
Stopping `couchdb`... (might take a while)
==> Successfully stopped `couchdb` (label: homebrew.mxcl.couchdb)
Code language: Bash (bash)
次に「couchdb」を試します。
$ couchdb
[info] 2020-05-15T01:45:24.109048Z couchdb@127.0.0.1 <0.239.0> -------- Preflight check: Asserting Admin Account
[info] 2020-05-15T01:45:24.111395Z couchdb@127.0.0.1 <0.239.0> -------- Apache CouchDB 3.1.0 is starting.
(省略)
Code language: Bash (bash)
localhost:5984/_utils にアクセスすると、ログイン画面が表示されました。ターミナルでCtrl + Cで停止します。
Ubuntu 18.04

couchdbサービスが起動しなかっので、dockerイメージを使ったよ。
リポジトリの登録
Ubuntu 18.04
$ sudo apt-get install -y apt-transport-https gnupg ca-certificates
$ echo "deb https://apache.bintray.com/couchdb-deb bionic main" \
| sudo tee -a /etc/apt/sources.list.d/couchdb.list
Code language: PHP (php)
Ubuntu 20.04
$ sudo apt-get install -y apt-transport-https gnupg ca-certificates
$ echo "deb https://apache.bintray.com/couchdb-deb focal main" \
| sudo tee -a /etc/apt/sources.list.d/couchdb.list
Code language: PHP (php)
インストール
リポジトリーキーをインストールします。
$ sudo apt-key adv --keyserver keyserver.ubuntu.com --recv-keys \
8756C4F765C9AC3CB6B85D62379CE192D401AB61
パッケージをインストールします。
$ sudo apt update
$ sudo apt install -y couchdb
インストールが終わると、設定画面が表示されます。タブキーで「了解」に移動して、Enterを押します。

「standalone」のまま、タブキーで「了解」に移動して、Enterを押します。

IPアドレス「127.0.0.1」のまま、タブで「了解」に移動して、Enterを押します。

adminユーザのパスワードを入力して、タブキーで「了解」に移動して、Enterを押します。


3.1.0がインストールされました。
ところが、sudo service couchdb status を見ると、起動していません。sudo service couchdb stop、sudo service couchdb start をしても、やはり起動しません。
いったんアンインストールしました。
$ sudo apt remove couchdb
$ sudo /bin/rm -rf /etc/couchdb
$ sudo /bin/rm -rf /opt/couchdb
Code language: Bash (bash)
インストール直後の設定画面を起動するために、設定ファイルを編集して、couchdbの項目を削除しました。config.dat は約10項目、約36行を削除しました。password.dataは2項目、約10行を削除しました。
$ sudo vim /var/cache/debconf/config.dat
$ sudo vim /var/cache/debconf/passwords.dat
Code language: Bash (bash)
再度インストール。adminパスワードを空欄にしたり、"password"にしたり、何回か試しましたが、やはり起動しませんでした。
インストールガイドには、couchdbユーザをadduserし、/home/couchdb 下に必要ファイルをコピーするように、とありますが、 ソースビルドしたときの手順と判断して、試していません。
書籍内コードなど
p166 寝心地のいいFuton
http://localhost:5984/_utils/ にアクセスすると、Web UIの Fauxton が表示されました。


書籍のバージョン1.1.1のFutonとは、だいぶ違うね。
musicデータベースを作成した直後の画面です。

Documentを新規作成した直後の画面です。JSONをソース入力します。

バージョン1.1.1のFutonには、JSON編集のためのFieldsタブとSourceタブがあるようだけど...

Fauxtonには、Fieldsタブはないようね。
がんばって、JSONソース編集するのよ。


旧UIのFutonってとういう意味?

日本語読みなら「フートン」かしら。
ソファーの一種で、日本語の布団から来ているようよ。

新UIのFauxtonは?

こちらも「フートン」。
faux は偽という意味で、フランス語由来だって。
偽のFutonというシャレかしら?
p170 cURLを使ったRESTfulなCRUD操作
curlの--silentオプションと、jqコマンドで、json結果を整形できます。
$ curl --silent http://localhost:5984 | jq
{
"couchdb": "Welcome",
"version": "2.3.1",
"git_sha": "c298091a4",
"uuid": "4df2d998bd6bc08f778d931863ff547c",
"features": [
"pluggable-storage-engines",
"scheduler"
],
"vendor": {
"name": "The Apache Software Foundation"
}
}
Code language: Bash (bash)
musicデータベース
$ curl --silent http://localhost:5984/music/ | jq
{
"db_name": "music",
"purge_seq": "0-g1AAAAEzeJzLYWBg4MhgTmHgzcvPy09JdcjLz8gvLskBCjMlKQDJJPv___9nJTLgUuMAUhOPV00eC5BkOACkgMruE1LXAFE3n5C6BRB1-wmpewBRh8d9iQxJ8vg9mQDyZD1ETRYAr_Vi9g",
"update_seq": "4-g1AAAAEzeJzLYWBg4MhgTmHgzcvPy09JdcjLz8gvLskBCjMlMiTJ____PyuRAYeCJAUgmWSPX40DSE08fjUJIDX1eNXksQBJhgYgBVQ2PyuRBa-6BRB1-wmZdwCi7j4hdQ8g6kDuywIAinpi-g",
"sizes": {
"file": 50382,
"external": 290,
"active": 957
},
"other": {
"data_size": 290
},
"doc_del_count": 0,
"doc_count": 1,
"disk_size": 50382,
"disk_format_version": 7,
"data_size": 957,
"compact_running": false,
"cluster": {
"q": 8,
"n": 1,
"w": 1,
"r": 1
},
"instance_start_time": "0"
}
Code language: Bash (bash)
ドキュメントIDをFauxtonで確認してコピペします。
$ curl --silent http://localhost:5984/music/8fd480a743fea05d026d8d31f50008e1 | jq
{
"_id": "8fd480a743fea05d026d8d31f50008e1",
"_rev": "4-93a101178ba65f61ed39e60d70c9fd97",
"name": "The Beatles",
"albums": [
{
"title": "Help!",
"year": 1965
},
{
"title": "Sgt. Pepper's Lonely Hearts Club Band",
"year": 1967
},
{
"title": "Abbey Road",
"year": 1969
}
]
}
Code language: JavaScript (javascript)
p173 1日目の宿題、やってみよう
1. cURLと任意の_idを使って、新しいドキュメントをmusicデータベースにPUTしてみよう。

_idは "abc1"

URLとjsonデータ、どちらにも _id を含めるのね
$ curl -i -X PUT "http://localhost:5984/music/abc1" \
-H "content-type: application/json" \
-d '{"_id": "abc1", "title": "sample"}'
HTTP/1.1 201 Created
Cache-Control: must-revalidate
Content-Length: 67
Content-Type: application/json
Date: Wed, 13 May 2020 16:20:06 GMT
ETag: "1-33ee4d6e6580d3416b53229622976f6e"
Location: http://localhost:5984/music/abc1
Server: CouchDB/2.3.1 (Erlang OTP/19)
X-Couch-Request-ID: f1c6215231
X-CouchDB-Body-Time: 0
{"ok":true,"id":"abc1","rev":"1-33ee4d6e6580d3416b53229622976f6e"}
Code language: Bash (bash)
2. curlを使って、任意の名前のデータベースを作成してみよう。

hoge3データベース
$ curl -i -X PUT "http://localhost:5984/hoge3"
HTTP/1.1 201 Created
Cache-Control: must-revalidate
Content-Length: 12
Content-Type: application/json
Date: Wed, 13 May 2020 16:00:18 GMT
Location: http://localhost:5984/hoge3
Server: CouchDB/2.3.1 (Erlang OTP/19)
X-Couch-Request-ID: 8b056fc366
X-CouchDB-Body-Time: 0
{"ok":true}
$ curl --silent "http://localhost:5984/hoge3" | jq
{
"db_name": "hoge3",
"purge_seq": "0-g1AAAAEzeJzLYWBg4MhgTmHgzcvPy09JdcjLz8gvLskBCjPlsQBJhgdA6j8QZCUy4FW3AKJuPyF1DRB18wmpOwBRdx-3uiQFIJlkj9dtSQkgNfV41SQyJMnjN8QBZEg8RE0WALbVYvY",
"update_seq": "0-g1AAAAEzeJzLYWBg4MhgTmHgzcvPy09JdcjLz8gvLskBCjMlMiTJ____PyuRAYeCJAUgmWSPX40DSE08fjUJIDX1eNXksQBJhgYgBVQ2n5C6BRB1-wmpOwBRd5-QugcQdSD3ZQEAiJJi9g",
"sizes": {
"file": 33960,
"external": 0,
"active": 0
},
"other": {
"data_size": 0
},
"doc_del_count": 0,
"doc_count": 0,
"disk_size": 33960,
"disk_format_version": 7,
"data_size": 0,
"compact_running": false,
"cluster": {
"q": 8,
"n": 1,
"w": 1,
"r": 1
},
"instance_start_time": "0"
}
Code language: Bash (bash)
そのデータベースを削除してみよう。

DELETEメソッドで削除できたよ
$ curl -i -X DELETE "http://localhost:5984/hoge3"
HTTP/1.1 200 OK
Cache-Control: must-revalidate
Content-Length: 12
Content-Type: application/json
Date: Wed, 13 May 2020 16:01:32 GMT
Server: CouchDB/2.3.1 (Erlang OTP/19)
X-Couch-Request-ID: d8ae9d1932
X-CouchDB-Body-Time: 0
{"ok":true}
$ curl --silent "http://localhost:5984/hoge3" | jq
{
"error": "not_found",
"reason": "Database does not exist."
}
Code language: Bash (bash)
3. cURLを使って、テキストドキュメントが添付されたドキュメントを作成してみよう。

ヒントをくださいー

FauxtonでUpload Attachmentを試してみてね

hogeデータベースを作成して、
ドキュメントを作成して、

そのドキュメントに、フィールド名=myfile1、内容="Hello world!" を添付しようかな。

ヘッダのIf-Matchで_rev指定しないと、conflictエラーだったよ。
$ curl -i -X PUT "http://localhost:5984/hoge/8fd480a743fea05d026d8d31f500e1cd/myfile1" \
-H "If-Match: 1-35c61f44bf0482bf60f056fa7bb990bc" \
-H "content-type: text/plain" \
-d "Hello world!"
HTTP/1.1 201 Created
Cache-Control: must-revalidate
Content-Length: 95
Content-Type: application/json
Date: Wed, 13 May 2020 16:10:07 GMT
Location: http://localhost:5984/hoge/8fd480a743fea05d026d8d31f500e1cd/myfile1
Server: CouchDB/2.3.1 (Erlang OTP/19)
X-Couch-Request-ID: e68eda3451
X-CouchDB-Body-Time: 0
{"ok":true,"id":"8fd480a743fea05d026d8d31f500e1cd","rev":"2-b5e58e3a4487729bd6c83e716e645bdb"}
Code language: Bash (bash)
最後に、その添付を返すようなcURLのリクエストを作って実行してみよう。
$ curl "http://localhost:5984/hoge/8fd480a743fea05d026d8d31f500e1cd/myfile1"
Hello world!
Code language: Bash (bash)
p175 最初のビューを作成する
Fauxtonのview作成画面に、[Run]ボタンはありません。
_temp_viewハンドラはなくなったようです。
$ curl -X POST http://localhost:5984/music/_temp_view \
> -H "Content-type: application/json" \
> -d '{"map": "function(doc){emit(doc._id, {rev:doc._rev})}"}'
{"error":"gone","reason":"Temporary views are not supported in CouchDB"}
Code language: Bash (bash)
p177の「ビューをデザインドキュメントとして保存する」が、Fauxtonでも操作できました。
p181 RubyでデータをCouchDBにインポート
Jamendoのxml.gzファイルは、
https://developer.jamendo.com/v3.0 >API Docsのページ内、
Old (deprecated) Apiの段落に見つかりました。
URLは、https://imgjam.com/data/dbdump_artistalbumtrack.xml.gz
gzサイズは21MB、xmlサイズは215MBでした。
$ wget https://imgjam.com/data/dbdump_artistalbumtrack.xml.gz
$ gunzip --keep dbdump_artistalbumtrack.xml.gz
$ ls -l
-rw-r--r-- 1 aoki aoki 215312064 12月 8 2014 dbdump_artistalbumtrack.xml
-rw-r--r-- 1 aoki aoki 20838691 12月 8 2014 dbdump_artistalbumtrack.xml.gz
Code language: JavaScript (javascript)
gem install libxml-rubyでエラーが
$ rbenv global
2.7.1
$ which ruby
/home/aoki/.rbenv/shims/ruby
$ gem install libxml-ruby couchrest
Fetching libxml-ruby-3.1.0.gem
Building native extensions. This could take a while...
ERROR: Error installing libxml-ruby:
ERROR: Failed to build gem native extension.
Code language: JavaScript (javascript)
apt で libxml2-dev をインストールしました。
$ sudo apt install libxml2-dev
$ gem install libxml-ruby couchrest
p185 2日目の宿題、やってみよう
1(省略)乱数がキーでバンド名が値のキーバリューペアをemitするmappter関数を作ってみよう。それをartistという名前のビューと一緒に _design/randomというデザインドキュメントに保存してみよう。
{
"_id": "_design/random",
"_rev": "2-b7c7eb2a30c02d4cf8dd06e1eebfb9a2",
"views": {
"artist": {
"map": "function (doc) {\n emit(doc.random, doc.name);\n}"
}
},
"language": "javascript"
}
Code language: JSON / JSON with Comments (json)
2 ランダムにアーティストを取得するcURLリクエストを作成してみよう。ヒント:startkeyパラメータが必要だ。コマンドライン ruby -e 'puts rand'を使って乱数を作ろう。
$ curl http://localhost:5984/music/_design/random/_view/artist?startkey=$(ruby -e 'puts rand')\&limit=1
Code language: Bash (bash)
3 (省略)artistビューにマッチする album、track、tagという3つのビューを作成してみよう。

「artistビューにマッチする」の意味がよくわからなかったよ
// album
function (doc) {
if ('name' in doc && 'albums' in doc) {
doc.albums.forEach(function (album) {
var val = { artist: doc.name, album: album.title || album.name };
var key = album.random;
emit(key, val);
});
}
}
Code language: JSON / JSON with Comments (json)
// track
function (doc) {
if ('name' in doc && 'albums' in doc) {
doc.albums.forEach(function (album) {
if ('tracks' in album) {
album_name = album.name || album.title;
album.tracks.forEach(function (track) {
var val = {
artist: doc.name,
album: album_name,
track: track.title || track.name
}
var key = track.random;
emit(key, val);
});
}
});
}
}
Code language: JSON / JSON with Comments (json)