次のようなデザインドキュメントを持っていると仮定します。
{ "meta": {"id": "_design/test"}, "views": { "view1": { "map": "function(doc, meta) { emit(meta.id, doc.value); }" } } }
そしてバケットには、{"value": 1}
というJSONの値を持つdoc1
というドキュメントと、{"value": 2}
というJSONの値を持つdoc2
というドキュメントの2つのドキュメントだけがあり、最初にstale=false
とinclude_docs=true
とgetでビューに問い合せます:
shell> curl -s 'http://localhost:9500/default/_design/test/_view/view1?include_docs=true&stale=false' | json_xs { "total_rows" : 2, "rows" : [ { "value" : 1, "doc" : { "json" : { "value" : 1 }, "meta" : { "flags" : 0, "expiration" : 0, "rev" : "1-000000367916708a0000000000000000", "id" : "doc1" } }, "id" : "doc1", "key" : "doc1" }, { "value" : 2, "doc" : { "json" : { "value" : 2 }, "meta" : { "flags" : 0, "expiration" : 0, "rev" : "1-00000037b8a32e420000000000000000", "id" : "doc2" } }, "id" : "doc2", "key" : "doc2" } ] }
そのあとで、ドキュメントdoc1
は{"value": 111111}
のJSONの値を持ち、ドキュメントdoc2
は{"value": 222222}
のJSONの値を持つように両方のドキュメントを更新します。そして、stale=update_after
(デフォルト)またはstale=ok
とgetでビューに問い合せます:
shell> curl -s 'http://localhost:9500/default/_design/test/_view/view1?include_docs=true' | json_xs { "total_rows" : 2, "rows" : [ { "value" : 1, "doc" : { "json" : { "value" : 111111 }, "meta" : { "flags" : 0, "expiration" : 0, "rev" : "2-0000006657aeed6e0000000000000000", "id" : "doc1" } }, "id" : "doc1", "key" : "doc1" }, { "value" : 2, "doc" : { "json" : { "value" : 222222 }, "meta" : { "flags" : 0, "expiration" : 0, "rev" : "2-00000067e3ee42620000000000000000", "id" : "doc2" } }, "id" : "doc2", "key" : "doc2" } ] }
各行に含まれるドキュメントは、各行の値フィールドと一致しない、つまり含まれているドキュメントは、最新の(更新された)バージョンですが、インデックスの行の値は、まだドキュメントの以前の(最初の)バージョンを反映しています。
なぜこのような振る舞いになるのでしょうか?これは、include_docs=true
が、クエリ時に各行でディスクから各ドキュメントの最新リビジョンがフェッチされるように作用するからです。ドキュメントの以前のリビジョンを含める方法はありません。最新のvbucketデータベースMVCCスナップショット(http://en.wikipedia.org/wiki/Multiversion_concurrency_control)を介して以前のリビジョンにアクセスすることはできませんし、ドキュメントの特定のリビジョンが配置されているvbucketデータベースの以前のMVCCスナップショットから効率的に見つけることはできません。さらに、vbucketデータベースのコンパクションは、以前のすべてのMVCCスナップショット(ドキュメントのリビジョン)を削除します。要するに、これはデータベースエンジンの意図的な設計上の限界となっています。
ここで完全な一貫性を保証する唯一の方法は、map関数によって出力される値に、それらのドキュメント自体を含めることです。しかも、stale=false
を使用したクエリは、100%信頼できるものではなく、インデックスが更新されたすぐあとで、行がクライアントにディスクからストリーミングされている場合、ドキュメントの更新と削除はまだ例のように同じ振る舞いの結果となります。