CouchDB HTTP ビュー API の概要
基本操作
ビューは、CouchDB のドキュメントに対してクエリーやレポート作成を行うときに使われる主要ツールです。
ビューは、JavaScript の関数で定義します。次に示すのは、最もシンプルな関数の例です。
function(doc) {
emit(null, doc);
}
詳細については、「CouchDB のビューの概要」を参照してください。
ビューの作成
永続的なビューを作成するには、まず関数を特別なデザイン・ドキュメントに保存する必要があります(特別な、と形容していますが、デザイン・ドキュメントは実際には「特別な」ドキュメントではなく、通常のドキュメントと同じで、特別な ID を持つドキュメントです)。デザイン・ドキュメントの ID は先頭が _design/ でなければならず、デザイン・ドキュメントには、ビュー関数を保持するための map メンバと、省略可能な reduce メンバを持つという特別なビュー属性があります。1 つのデザイン・ドキュメント内のすべてのビューは、そのいずれかに対してクエリーが実行されるたびに、インデックスが作成されます。
次に示すのは、all、by_lastname、および total_purchases というビューを定義したデザイン・ドキュメントです。
{
"_id":"_design/company",
"_rev":"12345",
"language": "javascript",
"views":
{
"all": {
"map": "function(doc) { if (doc.Type == 'customer') emit(null, doc) }"
},
"by_lastname": {
"map": "function(doc) { if (doc.Type == 'customer') emit(doc.LastName, doc) }"
},
"total_purchases": {
"map": "function(doc) { if (doc.Type == 'purchase') emit(doc.Customer, doc.Amount) }",
"reduce": "function(keys, values) { return sum(values) }"
}
}
}
language プロパティは、ビューの関数がどの言語で記述されているかを CouchDB 知らせます。CouchDB では、この情報をもとに適切なビュー・サーバー(couch.ini ファイルで指定されているもの)を選択します。デフォルトでは、JavaScript であると仮定します。
ビューの修正/変更
ビューを変更するには、ビューが保存されているドキュメントを修正し(「HTTP ドキュメント API」を参照してください)、修正後のドキュメントを新しいリビジョンとして保存します。
アクセス/クエリー
上のドキュメントをデータベースに保存すると、次の URL にアクセスすることで all ビューを取得できます。
たとえば、次のようにします。
GET /some_database/_design/company/_view/all HTTP/1.0 Date: Thu, 17 Aug 2006 05:39:28 +0000GMT
次のようなレスポンスが返ってきます。
HTTP/1.1 200 OK
Date: Thu, 17 Aug 2006 05:39:28 +0000GMT
Content-Length: 318
Connection: close
{
"total_rows": 3,
"offset": 0,
"rows": [{
"id":"64ACF01B05F53ACFEC48C062A5D01D89",
"key": null,
"value": {
"LastName":"Katz",
"FirstName":"Damien",
"Address":"2407 Sawyer drive, Charlotte NC",
"Phone":012555754211
}
}, {
"id":"5D01D8964ACF01B05F53ACFEC48C062A",
"key": null,
"value": {
"LastName":"Kerr",
"FirstName":"Wayne",
"Address":"123 Fake st., such and such",
"Phone":88721320939
}
}, {
"id":"EC48C062A5D01D8964ACF01B05F53ACF",
"key": null,
"value":
{
"LastName":"McCracken",
"FirstName":"Phil",
"Address":"1234 Fake st., such and such",
"Phone":7766552342
}
}
]
}
一時的なビュー
オンオフ・クエリー(CouchDB データベースに保存する必要のないビュー)は、特別なビューである _temp_view を介して実行できます。一時的なビューの使用が適しているのは開発中だけです。一時的なビューは、呼び出されるたびに計算を行うので非常に高価であり、データベース内のデータが増えるに従って処理速度も遅くなるため、最終的なコードでは一時的なビューの使用を避けるべきです。アドホックなビューでは解決できるのに永続的なビューでは解決できない問題があるときは、設計を考え直した方がよいでしょう。(TODO: 典型的な例とその解決方法の追加)
POST /some_database/_temp_view HTTP/1.0
Content-Length: 48
Date: Mon, 10 Sep 2007 17:11:10 +0200
Content-Type: application/json
{
"map" : "function(doc) { if (doc.foo=='bar') { emit(null, doc.foo); } }"
}
上のリクエストを実行すると、次のようなレスポンスが返ってきます。
{
"total_rows": 1,
"offset": 0,
"rows": [{
"id": "AE1AD84316B903AD46EF396CAFE8E50F",
"key": null,
"foo": "bar"
}
]
}
注:couchdb 0.9.0 では、_temp_view への POST で Content-Type: application/json を指定する必要があります。
クエリー・オプション
列には値のリストを入れることができます。列が保持できる値の数またはデータの量に制限はありません。
URL クエリー引数で使用できるものは、以下のとおりです。
GET
key=keyvalue
startkey=keyvalue
startkey_docid=docid
endkey=keyvalue
endkey_docid=docid
limit=返される行の最大値 これは、Trunk SVN r731159 以前では "count" と呼ばれていました。
stale=ok
descending=true
skip=スキップする行の数
group=true Version 0.8.0 以上
group_level=int
reduce=false Trunk のみ (0.9)
include_docs=true Trunk のみ (0.9)
POST
{"keys": ["key1", "key2", ...]} Trunk のみ (0.9)
key、startkey、および endkey は、JSON の表記方法に従って適切にエンコードされた値である必要があります(たとえば、文字列値の場合には startkey="string" とします)。
{"keys": ["key1", "key2", ...]} のような JASON オブジェクトを任意のユーザー定義のビューまたは _all_docs に POST すれば、指定されたキーの集合に一致する行だけを取得できます。行は、指定されたキーの順序に従って返されます。この機能と include_docs=true を組み合わせると、いわゆる multi-document-fetch 機能を実現できます。
?limit=0 を指定すると、データは取得できませんが、該当するビューのすべてのメタデータを取得できます(たとえば、ビューに含まれるドキュメントの数など)。
skip オプションは、小さな値を指定する場合にのみ使用するべきです。skip オプションで広い範囲のドキュメントをスキップするのは非効率なためです(startkey からインデックスをスキャンし、次に N 個の要素をスキップしますが、それでもこの操作を行うためにすべてインデックス値を読み取る必要があります)。ページ化を効率的に行うには、startkey と limit を使う必要があります。複数のドキュメントが同一のキーを返すことが予想される場合には、正しくページ化されるように、startkey に加えて startkey_docid を使う必要があります。行を一意に識別するのに、startkey だけでは不充分だからです。
stale オプションを使用すれば、パフォーマンスをさらに高めることができますが、その代償として、表示されるデータがすべて最新であるという保証はなくなります。stale オプションに ok を指定すると、CouchDB はビューのリフレッシュを(それが必要になても)実行できなくなります。このオプションを指定すると、ビュー・インデックスがメモリ内で利用可能である場合(すなわち、CouchDB が起動してから少なくとも一度、該当するビューに対するクエリーが実行されている場合)には、メモリ内のインデックスがたとえ古いものであっても、そのインデックスを使うよう CouchDB に指示することになります。そのため、やり取りの非常に多いビューの場合には、エンドユーザーは処理が早くなったように感じられますが、最新のデータを取得できていない可能性があります。ただし、ビュー・インデックスに対するポインタがメモリ内にない場合には、このオプションを指定しても、オプションが指定されなかった場合と動作は同じになります。エンドユーザーのクエリーに対してアプリケーション側で stale=ok を使う場合は、cron または「更新時のビューの再作成」で説明してるような通知プロセスを使って stale=ok なしにクエリーを実行し、妥当な程度までビューを最新のものにしておく必要があります。
ビューの行はキーによってソートされます。descending=true を指定すると、ソート順が逆になります。注意が必要なのは、descending はキーによる何らかのフィルタリングが実行される前に適用されることです。したがって、期待する結果を得るためには、startkey オプションと endkey オプションの値を入れ換える必要があります。ソートについては、「ビューの照合」に説明があります。
group オプションは、reduce 関数がキーごとの集合を返すか、単一の結果行を返すかを指定するのに使用します。
ビューに map 関数と reduce 関数の両方が含まれている場合、このビューに対してクエリーを実行すると、デフォルトでは redeuce 関数の結果が返されます。この場合、map 関数の結果は、クエリー・パラメータとして reduce=false を渡した場合にのみ取得できます。
include_docs オプションは、関連するドキュメントを含めるオプションです。ただし、このオプションを使うとレース・コンディションが発生する可能性があることに注意が必要です。ビュー・データの読み取りと対応するドキュメントの取得との間に、そのドキュメントが変更されている可能性があるからです。このような問題を少しでも解消したい場合には、emit(key, {"_rev": doc._rev}) のように、_rev 属性を付けてオブジェクトを返す必要があります。これでレース・コンディションの問題はいくぶん緩和されますが、それでも返されたドキュメントがすでに削除されている可能性は残ります(この場合、ドキュメントには "_deleted": true 属性が付けられます)。
ビューのデバッグ
ビューを作成するとき、CouchDB は受け取った JSON の構文をチェックしますが、ビュー関数それ自体については、JavaScript インタープリタによる構文のチェックは行われません。ビュー関数のいずれかに構文エラーがある場合、そのデザイン・ドキュメント内のビュー関数はすべて実行できなくなります。関数は一時的なビューでテストしてからデータベースに保存するとよいでしょう。
r660140 以降では、ビューで使用できる log 関数があり、この関数を使うと couch.log にログを残せます。log 関数はデバッグには役立ちますが、パフォーマンスを低下させます。したがって、プロダクション・システムではあまり使わない方がよいでしょう。
{
"map": "function(doc) { log(doc); }"
}
(形式不良な)ビューの実行は、現在のところ、CouchDB サーバーを不安定にするための最良の方法です。また、Futon Web クライアントも、ビューのエラーにうまく対処することができません。以下に、ビューの開発にあたって注意すべき点を示します。
プロダクション・システムではなく、独立した別のサーバー・インスタンス上でビューを開発します。
ログファイルの内容に注意します。ほとんどのエラーはログファイルだけに記録されています。
Futon Web クライアントの動作がおかしくなったら、Futon が作成したクッキーを削除してください。
一時的なビューで作業します。ビューが意図したとおりに動作することを確認してから、ビューを保存します。
テストではたかだか数百のドキュメントを対象に作業します。
Futon Web クライアントは、暗黙のうちに group=true をビューに追加する点に注意してください。
複数のビューでのコードの共有
複数のビューの間でコード/関数を共有することを目指す開発計画はありません。各ビュー関数は、それぞれのバイト表現に従って格納されます。したがって、関数では追加コードをロードしないことが大切で、もしこれを行うとバイト文字列は変わっていないのに動作が変わることになります。このような点を考慮して作成されたユーティリティとして、
CouchApp があります。