curl
CouchDB
CheatSheet

CouchDB のきほんチートシート curl 編

More than 1 year has passed since last update.


この解説の環境


  • 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/

image


  • note: 但し、この記事では futon による操作は扱わない


    • tips: もし CouchDB がリモートのサーバーで動作している場合 ssh-L 5984:remote.example.net:5984 のようにパラメーターを追加、トンネリングし、 futon にローカルのリッチなウェブブラウザーで接続すると捗るでしょう。たぶん w3m とかだと厳しいでしょう。




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: ? の後はいわゆるクエリーで keyinclude_docs など複数のパラメーターを & で組み合わせて投げられる

  • note: key には他に keys, startkey または startkey_docidendkey または 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: languagejavascript のほか 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 回りの大きな仕様変更があった



  • 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 の時と同様



  • 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 の歴史的な興味であれ、触れてみようという方のとっかかりくらいには役立てば幸いです。