この解説の環境
- CouchDB-1.6.1
- デフォルトの
127.0.0.1:5984
でサービスが稼働
- デフォルトの
- Ubuntu-16.04
- curl-7.47.0
諸注意
- 記事中の rev 値はすべて例であり、実行環境により異なる値が生成されるものです。(コピペで操作練習などする場合はこの点に気をつけて下さい。)
- 「基本操作」、「応用操作」、「初級」、「中級」、「変態」などは何れも「この記事の中での度合いの話」です。より多くの知識が必要になれば Apache - CouchDB Wiki を読むなり stackoverflow しましょう。
- Qiita の特性上ドキュメントであってシートではありませんがチートシート的に基本操作をざくざくと掲載したドキュメントです。
基本操作
動作確認: GET host:port
curl -X GET 127.0.0.1:5984
{"couchdb":"Welcome","uuid":"4fa79ddb179218126c1245256d74878f","version":"1.6.1","vendor":{"version":"16.04","name":"Ubuntu"}}
組み込みウェブGUI Futon
の動作確認
http://127.0.0.1:5984/_utils/
- note: 但し、この記事では futon による操作は扱わない
- tips: もし CouchDB がリモートのサーバーで動作している場合
ssh
に-L 5984:remote.example.net:5984
のようにパラメーターを追加、トンネリングし、 futon にローカルのリッチなウェブブラウザーで接続すると捗るでしょう。たぶんw3m
とかだと厳しいでしょう。
- tips: もし CouchDB がリモートのサーバーで動作している場合
database
作成: PUT host:port/database
curl -X PUT 127.0.0.1:5984/test
return 例(成功):
{"ok":true}
return 例(失敗:既に database が存在している):
{"error":"file_exists","reason":"The database could not be created, the file already exists."}
削除 DELETE host:port/database
curl -X DELETE 127.0.0.1:5984/test
return 例(成功):
{"ok":true}
return 例(失敗: database が存在しない):
{"error":"not_found","reason":"missing"}
document
取得: GET host:port/database/document
curl -X GET 127.0.0.1:5984/test/aaa
{"_id":"aaa","_rev":"1-cd869af19a904a384902a38ee92962f0","xxx":111,"yyy":222,"zzz":{"a":3,"b":4,"c":[5,6,7]}}
作成: PUT host:port/database/document + JSONデータ
以下の何れの方法で可能。PUT
の場合は URL に _id
となる値が必須。 POST
の場合に、データに "_id"
が含まない場合は "id"
は自動生成となる。何れの場合も結果に生成された "id
" と "rev" が返る。
curl -X PUT 127.0.0.1:5984/test/aaa -d '{"xxx":111,"yyy":222,"zzz":{"a":3,"b":4,"c":[5,6,7]}}'
curl -X POST 127.0.0.1:5984/test -H 'content-type: application/json' -d '{"xxx":111,"yyy":222,"zzz":{"a":3,"b":4,"c":[5,6,7]}}'
return 例(成功):
{"ok":true,"id":"aaa","rev":"1-cd869af19a904a384902a38ee92962f0"}
return 例(失敗: database が存在しない)
{"error":"not_found","reason":"no_db_file"}
return 例(失敗: 投げたJSONデータが不正)
{"error":"bad_request","reason":"invalid_json"}
更新: PUT host:port/database/document + JSONデータ + rev値
以下の方法は何れも等価。
curl -X PUT 127.0.0.1:5984/test/aaa?rev="1-cd869af19a904a384902a38ee92962f0" -d { "hoge": "fuga" }
curl -X PUT 127.0.0.1:5984/test/aaa -d { "_rev": "1-cd869af19a904a384902a38ee92962f0", "hoge": "fuga" }
return 例(成功):
{"ok":true,"id":"aaa","rev":"2-1f448729059b06b92dfee732d83f031c"}
return 例(失敗: rev値が不正):
{"error":"conflict","reason":"Document update conflict."}
return 例(失敗: rev値の書式が不正):
{"error":"bad_request","reason":"Invalid rev format"}
削除: DELETE host:port/database/document + rev値
以下の方法は何れも等価。
curl -X DELETE 127.0.0.1:5984/test/aaa?rev="1-cd869af19a904a384902a38ee92962f0"
curl -X PUT 127.0.0.1:5984/test/aaa -d { "_rev": "1-cd869af19a904a384902a38ee92962f0", "_deleted": true }
return 例(成功):
{"ok":true,"id":"aaa","rev":"2-1f448729059b06b92dfee732d83f031c"}
return 例(失敗: rev値が不正):
{"error":"conflict","reason":"Document update conflict."}
return 例(失敗: rev値の書式が不正):
{"error":"bad_request","reason":"Invalid rev format"}
- note: document の削除の"実態"は「削除マークを有効にして更新」しているだけ
- そのため、削除した document と同じ id の document を作ると rev 値だけみれば削除時点+1で"復活"したかのようになる
存在と rev 値のみ確認
- note: CouchDB は HTTP RESPONSE HEADER にも有用な使い方、情報の提供がある
curl -X GET 127.0.0.1:5984/test/aaa --head
aaa が存在する時:
HTTP/1.1 200 OK
Server: CouchDB/1.6.1 (Erlang OTP/18)
ETag: "8-0517d1736e63d34d91db334b97a2a94b"
Date: Tue, 30 Aug 2016 20:21:39 GMT
Content-Type: text/plain; charset=utf-8
Content-Length: 58
Cache-Control: must-revalidate
- note:
ETag
に rev 値が得られている
aaa が存在しない時:
HTTP/1.1 404 Object Not Found
Server: CouchDB/1.6.1 (Erlang OTP/18)
Date: Tue, 30 Aug 2016 20:21:54 GMT
Content-Type: text/plain; charset=utf-8
Content-Length: 41
Cache-Control: must-revalidate
添付追加
curl -X PUT 127.0.0.1:5984/test/aaa/hoge.png?rev="2-1f448729059b06b92dfee732d83f031c" -H 'content-type: image/png' --data-binary @./hoge.png
note: curl
の -d
系パラメーターの値に @
はファイルからの読み出し
return 例(成功):
{"ok":true,"id":"aaa","rev":"3-45f180d2f1d7873ff57d0eff3f08c6ba"}
添付削除
curl -X DELETE 127.0.0.1:5984/test/aaa/hoge.png?rev="3-45f180d2f1d7873ff57d0eff3f08c6ba"
return 例(成功):
{"ok":true,"id":"aaa","rev":"4-8858de7dc39c5d3453df99460a10eb96"}
return 例(失敗: rev付け忘れ):
{"error":"conflict","reason":"Document update conflict."}
応用操作・初級
一括操作: POST + _bulk_docs
一括で個別に操作: POST + _bulk_docs
いわゆる SIMD 処理。以下は「documentを作成」という SI に [ { "_id": "bbb", "value": "456" }, { "value": "789" } ]
と2件の MD を投げる例。
- note 1:
"_id"
の無いデータを投げると "_id
" は自動生成される(host:port/database/document でいう document の部分) - note 2: 更新操作を行いたい場合はデータへの rev 値を入れ忘れに注意
- note 3: 削除操作を行いたい場合はデータへの rev 値に加えて
"_deleted": true
を追加して投げる - note 4: デフォルト動作の _bulk_docs の処理はデータごと個別に行われ成否はデータごとに発生する
curl -X POST 127.0.0.1:5984/test/_bulk_docs -H 'content-type: application/json' -d '{ "docs": [ { "_id": "bbb", "value": "456" }, { "value": "789" } ] }'
return 例(全て成功):
[{"ok":true,"id":"bbb","rev":"1-dc0e9d8e2fd80f086d4cc36b8eeae9e5"},{"ok":true,"id":"56b000058f5a060388a4da64e7002d11","rev":"1-0d145e34d9c50794b0a54ac3feef0d3a"}]
return 例(一部は成功、一部は失敗):
[{"id":"bbb","error":"conflict","reason":"Document update conflict."},{"ok":true,"id":"56b000058f5a060388a4da64e7003056","rev":"1-0d145e34d9c50794b0a54ac3feef0d3a"}]
一括でアトミックに操作: POST _bulk_docs
+ all_or_nothing
_bulk_docs のデータに "all_or_nothing": true
を付けると投げた操作全体のアトミック操作となる。
curl -X POST 127.0.0.1:5984/test/_bulk_docs -H 'content-type: application/json' -d '{ "all_or_nothing": true, "docs": [ { "_id": "bbb", "value": "456", "value2": 654 }, { "value": "789", "_deleted":true } ] }'
return 例(偽性の成功≃事実上の失敗: 一部は成功、一部は失敗 ):
既に "_id": "bbb"
が存在する database に対して ↑curl
コマンド例を投げた場合にも以下のように"全て"のデータに対する処理が "ok":true
で返ってくる。しかし、 "rev"
が更新されていない事
でも分かるように実際には処理は成功していない。
[{"ok":true,"id":"bbb","rev":"1-956fc4802a21507c64768b30cfce1d15"},{"ok":true,"id":"56b000058f5a060388a4da64e7007c52","rev":"1-7a6605c8b61217d1d8785683b9790719"}]
ドキュメントの検索: GET + _all_docs
id と rev のみ取得: GET + _all_docs
curl -X GET 127.0.0.1:5984/test/_all_docs
return 例(成功):
{"total_rows":3,"offset":0,"rows":[
{"id":"aaa","key":"aaa","value":{"rev":"1-c8227456e13a740a3a950be456a85f21"}},
{"id":"bbb","key":"bbb","value":{"rev":"1-ea6f81f73a3bf9c1dc3391565b740870"}},
{"id":"ccc","key":"ccc","value":{"rev":"1-5bac6f87d40c8d92da4a0586361bb950"}}
]}
id と rev のみ取得: GET + _all_docs
+ include_docs
curl -X GET 127.0.0.1:5984/test/_all_docs?include_docs=true
- note:
true
は暗黙の型変換の期待や省略時のデフォルト値など無いのでtrue
まで書く
return 例(成功):
{"total_rows":3,"offset":0,"rows":[
{"id":"aaa","key":"aaa","value":{"rev":"1-c8227456e13a740a3a950be456a85f21"},"doc":{"_id":"aaa","_rev":"1-c8227456e13a740a3a950be456a85f21","k1":100,"k2":101,"k3":102}},
{"id":"bbb","key":"bbb","value":{"rev":"1-ea6f81f73a3bf9c1dc3391565b740870"},"doc":{"_id":"bbb","_rev":"1-ea6f81f73a3bf9c1dc3391565b740870","k1":200,"k2":201,"k3":202}},
{"id":"ccc","key":"ccc","value":{"rev":"1-5bac6f87d40c8d92da4a0586361bb950"},"doc":{"_id":"ccc","_rev":"1-5bac6f87d40c8d92da4a0586361bb950","k1":300,"k2":301,"k3":302}}
]}
特定の key (≃ id )のみ取得: GET + _all_docs
+ key
curl -X GET '127.0.0.1:5984/test/_all_docs?key={"aaa","ccc"}&include_docs=true'
- note:
?
の後はいわゆるクエリーでkey
やinclude_docs
など複数のパラメーターを&
で組み合わせて投げられる - note:
key
には他にkeys
,startkey
またはstartkey_docid
とendkey
またはendkey_docid
といった亜種もある --> CouchDB Wiki - Query Options
return 例(成功):
[1/2]: 127.0.0.1:5984/test/_all_docs?key="aaa"&include_docs=true -->
--curl--127.0.0.1:5984/test/_all_docs?key="aaa"&include_docs=true
{"total_rows":3,"offset":0,"rows":[
{"id":"aaa","key":"aaa","value":{"rev":"1-c8227456e13a740a3a950be456a85f21"},"doc":{"_id":"aaa","_rev":"1-c8227456e13a740a3a950be456a85f21","k1":100,"k2":101,"k3":102}}
]}[2/2]: 127.0.0.1:5984/test/_all_docs?key="ccc"&include_docs=true -->
--curl--127.0.0.1:5984/test/_all_docs?key="ccc"&include_docs=true
{"total_rows":3,"offset":2,"rows":[
{"id":"ccc","key":"ccc","value":{"rev":"1-5bac6f87d40c8d92da4a0586361bb950"},"doc":{"_id":"ccc","_rev":"1-5bac6f87d40c8d92da4a0586361bb950","k1":300,"k2":301,"k3":302}}
]}
応用操作・中級
design/view (≃ Map Reduce)
- note: 検索機能はいわゆる Map Reduce 関数を定義した view を database の design に登録して使う
- map: 射影変換(≃「入力」を「ごにょごにょ変換」して「出力」)
- reduce: 集計(≃「入力」を「整理」して「出力」)
任意の条件の絞り込み検索を行う: view/map emit
view の作成
- note 2: デザインをワンライナーで書くのは辛いので .json ファイルを用意して
curl -d @
で投げる事にします。
d1.json:
{ "language": "javascript"
, "views":
{ "v1":
{ "map":
"function ( d )
{
if ( d.k1 > 200 )
emit( d._id, { 'k1': d.k1, 'k2 + k3': d.k2 + d.k3 } );
}"
}
, "v2":
{ "map":
"function ( d )
{
if ( d.k2 > 200 )
emit( d._id + '-' + d.k3, null );
}"
}
}
}
- note 1: 組み込み関数
emit
のシグネチャーをわかりやすく書くと、function emit( key, value );
- note 2:
language
はjavascript
のほかcoffeescript
でも書ける事になっている- 省略する事も可能で、その場合は
javascript
として扱われる
- 省略する事も可能で、その場合は
curl -X PUT 127.0.0.1:5984/test/_design/d1 -H 'content-type: application/json' -d @./d1.json
return(成功):
{"ok":true,"id":"_design/d1","rev":"1-b0a42e17ff9d67143d6ef16174ee894c"}
- note: design も他の一般的なドキュメント同様に作成・更新・削除など行える
design の取得
curl -X GET 127.0.0.1:5984/test/_design/d1
return:
{"_id":"_design/d1","_rev":"1-b0a42e17ff9d67143d6ef16174ee894c","language":"javascript","views":{"v1":{"map":"function ( d ) { if ( d.k1 > 200 ) emit( d._id, { 'k1': d.k1, 'k2 + k3': d.k2 + d.k3 } ); }"},"v2":{"map":"function ( d ) { if ( d.k2 > 200 ) emit( d._id + '-' + d.k3, null ); }"}}}
見難いので JSON FORMATTER & VALIDATOR で format すると:
{
"_id":"_design/d1",
"_rev":"1-b0a42e17ff9d67143d6ef16174ee894c",
"language":"javascript",
"views":{
"v1":{
"map":"function ( d ) { if ( d.k1 > 200 ) emit( d._id, { 'k1': d.k1, 'k2 + k3': d.k2 + d.k3 } ); }"
},
"v2":{
"map":"function ( d ) { if ( d.k2 > 200 ) emit( d._id + '-' + d.k3, null ); }"
}
}
}
view の使用
curl -X GET 127.0.0.1:5984/test/_design/d1/_view/v1
return:
{"total_rows":1,"offset":0,"rows":[
{"id":"ccc","key":"ccc","value":{"k1":300,"k2 + k3":603}}
]}
見難いので JSON FORMATTER & VALIDATOR で format すると:
{
"total_rows":1,
"offset":0,
"rows":[
{
"id":"ccc",
"key":"ccc",
"value":{
"k1":300,
"k2 + k3":603
}
}
]
}
他の view の例:
curl -X GET 127.0.0.1:5984/test/_design/d1/_view/v2
return:
{"total_rows":2,"offset":0,"rows":[
{"id":"bbb","key":"bbb-202","value":null},
{"id":"ccc","key":"ccc-302","value":null}
]}
JSON FORMATTER & VALIDATOR で format すると:
{
"total_rows":2,
"offset":0,
"rows":[
{
"id":"bbb",
"key":"bbb-202",
"value":null
},
{
"id":"ccc",
"key":"ccc-302",
"value":null
}
]
}
任意の条件の集計を行う: view/reduce
reduce で集計する view を新たな design として追加
- design の追加ではなく既存の design を更新して view を追加しても構わない
- design の view の map, reduce は必要なら定義すれば良いし、それぞれ不要ならば定義しなくて構わない
map も reduce もする view を定義した小さな d2.json:
{ "views":
{ "v3":
{ "map" : "function ( d ) { emit( d._id, d.k1 + d.k2 + d.k3 ) }"
, "reduce": "function ( k, v, r ) { return sum( v ) }"
}
}
}
d2.json を d2 として追加:
curl -X PUT 127.0.0.1:5984/test/_design/d1 -d @./d2.json
{"ok":true,"id":"_design/d2","rev":"1-0a71c65253d237bbc66aa4df3b1f2d11"}
d2 を確認:
curl -X GET 127.0.0.1:5984/test/_design/d2
{"_id":"_design/d2","_rev":"1-0a71c65253d237bbc66aa4df3b1f2d11","views":{"v3":{"map":"function ( d ) { emit( d._id, d.k1 + d.k2 + d.k3 ) }","reduce":"function ( k, v, r ) { return sum( v ) }"}}}
{
"_id":"_design/d2",
"_rev":"1-0a71c65253d237bbc66aa4df3b1f2d11",
"views":{
"v3":{
"map":"function ( d ) { emit( d._id, d.k1 + d.k2 + d.k3 ) }",
"reduce":"function ( k, v, r ) { return sum( v ) }"
}
}
}
- note:
reduce
のシグニチャーをわかりやすく書くとfunction ( keys, values, is_intermediate )
といったところ-
is_intermediate
に-
false
が渡されて呼ばれる時は:reduce( [ [ key1, id1 ], ... ], [ value1, ... ], false )
-
true
が渡されて呼ばれる時は:reduce( null, [ intermediate1, ... ], true )
- もう少し詳しい解説が欲しければ Couch Wiki - Reduce Function をどうぞ
-
-
view の使用
curl -X GET 127.0.0.1:5984/test/_design/d2/_view/v3
{"rows":[
{"key":null,"value":1809}
]}
整形して見ると:
{
"rows":[
{
"key":null,
"value":1809
}
]
}
ちなみに、↑この時は↓こんなドキュメント群が詰まった test1 だったので、
{"id":"aaa","key":"aaa","value":{"rev":"1-c8227456e13a740a3a950be456a85f21"},"doc":{"_id":"aaa","_rev":"1-c8227456e13a740a3a950be456a85f21","k1":100,"k2":101,"k3":102}},
{"id":"bbb","key":"bbb","value":{"rev":"1-ea6f81f73a3bf9c1dc3391565b740870"},"doc":{"_id":"bbb","_rev":"1-ea6f81f73a3bf9c1dc3391565b740870","k1":200,"k2":201,"k3":202}},
{"id":"ccc","key":"ccc","value":{"rev":"1-5bac6f87d40c8d92da4a0586361bb950"},"doc":{"_id":"ccc","_rev":"1-5bac6f87d40c8d92da4a0586361bb950","k1":300,"k2":301,"k3":302}}
]}
ドキュメントごとに map の段階で↓のように [ value1, ... ]
がそれぞれに処理され、
100 + 101 + 102 = 303 ( = value1 )
200 + 201 + 202 = 603 ( = value2 )
300 + 301 + 302 = 903 ( = value3 )
続いて↑の [ value1, ... ]
が↓のように values
に入れられ reduce が処理され、
303 + 603 + 903 = 1809 ( = d2/v3 の map -> reduce 後の最終的な結果としての value )
となったものです。
変態操作(まちがった事は言ってない)
ごめんなさい変態というか整形です。
document の出力を JSON -> なにか に整形して出力: show
- note: design の shows にドキュメントを任意の関数を噛ませて射影変換して出力する機能を入れられる
- 関数のシグニチャーは
function ( document, request )
- document は GET されるドキュメント
- request は関数が呼ばれる発端となるリクエスト情報で、 request.query はじめいろいろ(本項で後述†)と詰まっている
- 関数のシグニチャーは
d3.json:
{ "shows":
{ "s1":
"function ( d, r )
{
var hs = { };
var b;
if ( ! d )
b = 'document is n/a.';
else if ( r.query.csv )
{
hs[ 'content-type' ] = 'text/csv';
b = [ d.k1, d.k2, d.k3 ].reduce( function ( a, b ) { return a + ', ' + b; } );
}
else
{
hs[ 'content-type' ] = 'application/json';
b = JSON.stringify( d );
}
return { 'headers': hs, 'body': b + '\\n' };
}"
}
}
- note: この関数は eval される
"
囲いの文字列の中にあるため改行文字のためのエスケープそれ自信もエスケープしないと eval 対象となる内部に関数定義された文字列内にエスケープ文字を入れられないため'\\n'
となる点に注意
request の中身†
↓こんなのを仕込むと実際の挙動として観測できる
function ( d, r ) { return { 'body': JSON.stringify( r ) } }
↑から中略、仕込んだ show でドキュメント aa
を GET してみるとこうなる↓
{"info":{"db_name":"test","doc_count":8,"doc_del_count":0,"update_seq":100,"purge_seq":0,"compact_running":false,"disk_size":446568,"data_size":8112,"instance_start_time":"1472498362522313","disk_format_version":6,"committed_update_seq":100},"id":"aa","uuid":"56b000058f5a060388a4da64e7024e5d","method":"GET","requested_path":["test","_design","d4","_show","s1","aa"],"path":["test","_design","d4","_show","s1","aa"],"raw_path":"/test/_design/d4/_show/s1/aa","query":{},"headers":{"Accept":"/","Host":"127.0.0.1:5984","User-Agent":"curl/7.47.0"},"body":"undefined","peer":"127.0.0.1","form":{},"cookie":{},"userCtx":{"db":"test","name":null,"roles":["_admin"]},"secObj":{}}
↑を整形すると↓:
{
"info":{
"db_name":"test",
"doc_count":8,
"doc_del_count":0,
"update_seq":100,
"purge_seq":0,
"compact_running":false,
"disk_size":446568,
"data_size":8112,
"instance_start_time":"1472498362522313",
"disk_format_version":6,
"committed_update_seq":100
},
"id":"aa",
"uuid":"56b000058f5a060388a4da64e7024e5d",
"method":"GET",
"requested_path":[
"test",
"_design",
"d4",
"_show",
"s1",
"aa"
],
"path":[
"test",
"_design",
"d4",
"_show",
"s1",
"aa"
],
"raw_path":"/test/_design/d4/_show/s1/aa",
"query":{
},
"headers":{
"Accept":"*/*",
"Host":"127.0.0.1:5984",
"User-Agent":"curl/7.47.0"
},
"body":"undefined",
"peer":"127.0.0.1",
"form":{
},
"cookie":{
},
"userCtx":{
"db":"test",
"name":null,
"roles":[
"_admin"
]
},
"secObj":{
}
}
- note 1: show として定義する関数で使いたければこれらの情報を request から引っ張りだして使える
- note 2: show の return の中身はいわゆる response 構造なので body 以外にも何かと設定したり、 BASE64 エンコードでバイナリーを出力もできる: CouchDB The Definitive Guide - Show Functions
view の出力を JSON -> なにか に整形して出力: list
- note 1: view の結果を整形する list を lists に含んだ design を定義して使う
- note 2: couch-0.10 以降とそれ以前では仕様が list 回りの大きな仕様変更があった
- この記事では couch-0.10 以降のスタイルでのみ紹介します
- couch-0.9 以下の古いスタイルの情報は Couch Wiki - Listing Views with CouchDB 0.9 、日本語の紹介記事では @IT - ゆったリラックス! CouchDBがあるところ(2) (2009-10-26) など
- note 3: list は view の結果を整形する機能なので design には少なくとも1つの view と list の両方が必要
d5.json:
{ "views": { "v1": { "map": "function( d ) { emit( null, d.k1 + d.k2 + d.k3 ) }" } }
, "lists":
{ "l1":
"function ( h, r )
{
start( { 'headers': { 'content-type': 'text/html' } } );
send( '<ul>\\n' );
var row;
while ( row = getRow() )
send( ' <li>' + row.value + '\\n' );
send( '</ul>\\n' );
}"
}
}
- note 1: ↑は k1 + k2 + k3 を出力する map のみの view + HTML として
<ul><li>...</ul>
に整形する list で構成 - note 2: list の関数シグニチャーは
function ( header, request )
- header:
{"total_rows":3,"offset":0}
こんなのが入ってる - request: show の時と同様
- header:
- note 4:
getRow()
は組み込み関数で view の出力結果を1件読み出せる- 基本的に使うのは
.value
- 他に
.id
と.key
が定義されて飛んで来る
- 基本的に使うのは
- note 3:
send
は組み込み関数で、呼び付けると引数で渡されたオブジェクトの toString 結果を出力-
{ ... }
オブジェクトをそのまま投げても[object Object]
と出るだけなので注意 - 文字列や数値を投げないとあまり意味は無い
-
curl -X GET 127.0.0.1:5984/test/_design/d5/_list/l1/v1
<ul>
<li>303
<li>603
<li>903
</ul>
- note: 使う時は
host:port/database/_design/my_design_1/_list/my_list_1/my_view_1
といった文法で database に対して design の list に view の結果を出力させる
参考
きほんてきに CouchDB wiki を見るのが安全:
wiki よりも個別の機能ごとに少し詳しく知りたい時にはこちらが役に立つ(この記事からの参考として直接的なところを一部抜粋してリンクを列挙するが、CouchDBを"使い倒す"つもりであればもちろん他の項も読むとより幸せになれる):
どうしても日本語の優しい入門記事が読みたいという場合にはこちらがよいかも(但し記事が古い点に少々注意):
基本はわかっていて簡潔な API リファレンスだけあればいいんじゃーとなったなら:
おまけ:
著者のただのふんわり話です。
はじめてカウチを触ったのは出た頃の10年くらい前。新しいものにはとりあえず何でも触れていた頃、時代はまだウェブではHTML4じゃなくてXHTML-1.0でstrictでとか、.netが今とは違う意味でちょー元気もりもりやる気まんまんで盛り上がってくる黎明期で、Silverlightもこれからだぞーって頃だった(当時はまだWPF/Eと呼ばれてFLASHを本気で駆逐する先鋒として生まれようとしていた頃だった)。
今回、仕事でカウチを使う機会が得られたので、プロジェクトチーム向けの導入記事の側面も兼ねてこのドキュメントを書きました。ついで、仕事であれ、プライベートの技術的な興味、あるいは NoSQL の歴史的な興味であれ、触れてみようという方のとっかかりくらいには役立てば幸いです。