CouchDB の show フォーマットを使った時の罠
1時間ぐらいはまった。
結論。CouchDBでドキュメントを更新(HTTP PUT)をするときに、ドキュメントが _revisions メンバーを持つ場合、厳しいリビジョンチェックが行われるので注意。
(1) こんな具合に、ドキュメントのJSONをHTMLに埋め込むようなテンプレートを使う。
// template/test.html var doc = <%= toJSON(page) %>;
(2) このテンプレートを、show フォーマット機能を使ってHTML出力する。
function(doc, req) { // !json templates.page // !code vendor/couchapp/template.js // !code vendor/couchapp/path.js if( doc ){ try{ var html = template(templates.page, { page : doc, assetPath: assetPath() }); return {body:html}; (略)
この場合、page オブジェクト(doc) は、_revisions というプロパティを持つようだ。0.9.0 からだと思いまする。
{"_id":"pages:top","_rev":"1-1962362123", // (略) "_revisions":{"start":1,"ids":["1962362123"]}}
で、(1)で実際にはき出されるコードは、次のようになる。
var doc = {"_id":"pages:top","_rev":"1-1962362123", // (略) "_revisions":{"start":1,"ids":["1962362123"]}}
ここで jquery.couch.db オブジェクトを使って(CouchAppの初期化に参照可能なデータベース接続オブジェクト)、saveDocメソッド経由で、ドキュメントを保存する。
app.db.saveDoc(doc);
これは、成功する。しかし、jquery.couch.db では、次のように、保存の成功時に、_id, _rev 自体は更新するが、_revisions はケアしない。つまり、上記のコード実行後、docオブジェクトは次のような状況になりうる。
{"_id":"pages:top","_rev":"2-2038989889", // (略) "_revisions":{"start":1,"ids":["1962362123"]}}
_rev が 2-xxxxxx となっているので、本来 _revisions は {"start": 2, "ids": ["2038989889", "1962362123"]} となっていなければならないが、そうはなっていないのだ。
で、こんな状態で再び、
app.db.saveDoc(doc);
と投げると、409 Conflict が起こりました。
対策は簡単で、show フォーマトでテンプレート適用前に、_revisions をundefinedにすると、JSONに出力されなくて、厳密なリビジョンチェックが行われなくなります。
function(doc, req) { // !json templates.page // !code vendor/couchapp/template.js // !code vendor/couchapp/path.js if( doc ){ try{ doc._revision = undefined; // <-- _revisions はクライアントに返さない。 var html = template(templates.page, { page : doc, assetPath: assetPath() }); return {body:html};