SQLステートメント内のWHERE
句は個々のレコードを選ぶための選択基準を形成しています。ビュー内では、データの問い合わせはmap()
関数によって生成されるkey
の内容と構造によって制御されます。
一般的に、各WHERE
句のために、生成されたビューのキーにある対応するフィールドを含める必要があり、そのあとで選択したいデータを示すためにkey
、keys
もしくはstartkey
/endkey
の組み合わせを使用します。複数のフィールドに問い合わせを実行するときは、複雑になります。このために使用できる様々な方法があります。
最も簡単な方法は特定の組み合わせを選択できる方がよいかどうか、もしくは範囲か複数の選択を実行したいかどうかを決めることです。たとえば、レシピのデータベースを使用して、 'carrot'という食材を使用して、20分ちょうどで調理できるレシピを選択したい場合、map()
関数で2つのフィールドを指定することができます:
function(doc, meta) { if (doc.ingredients) { for(i=0; i < doc.ingredients.length; i++) { emit([doc.ingredients[i].ingredient, doc.totaltime], null); } } }
次に、クエリは2つの選択値の配列とします:
?key=["carrot",20]
これは次のSQLクエリと同じです:
SELECT recipeid FROM recipe JOIN ingredients on ingredients.recipeid = recipe.recipeid WHERE ingredient = 'carrot' AND totaltime = 20
しかし、もしニンジンを含んでいて、20分以内に準備できるレシピを選択するクエリを実行したい場合、同じmap()
関数を使用して範囲クエリを実行できます。
?startkey=["carrot",0]&endkey=["carrot",20]
これは幸いにもビューのソートメカニズムがニンジンと連番で情報をソートして出力するからです。
複雑なクエリはより難しくなります。ニンジンとごはんを使って、さらに20分以内に準備できるレシピを選択したいとしたらどうなりますか?
上記のような標準的なmap()
関数は有効ではありません。両方の食材の範囲クエリは2つの間の食材のすべてをリストしてしまいます。しかし、ここで利用できるソリューションがいくつかあります。まず、タイミングの選択を処理するための最も簡単な方法は、指定された時間内で準備できるレシピを明示的に選択するようなビューを作成することです。つまり:
function(doc, meta) { if (doc.totaltime <= 20) { ... } }
このアプローチはクエリを厳しく制限するように思われますが、複数のビューを作成することができるので、10分のビュー、20分のビュー、30分のビューなど選択した間隔でビューを作成できるということを忘れないでください。誰もが本当に17分で調理できるレシピを選択したいとは考えにくいので、そのような粒度の選択肢はやりすぎです。
複数の食材は解決がより困難です。1つの方法は、2つのクエリの実行とデータのマージをクライアントで実行することです。たとえば、map()
関数を次のようにします:
function(doc, meta) { if (doc.totaltime && doc.totaltime <= 20) { if (doc.ingredients) { for(i=0; i < doc.ingredients.length; i++) { emit(doc.ingredients[i].ingredient, null); } } } }
各ビューが出力するドキュメントIDを比較し、カウントをとることで、各食材に対する二つのクエリの結果を簡単にマージできます。
もうひとつはネストしたループの中で食材を二回出力する方法です:
function(doc, meta) { if (doc.totaltime && doc.totaltime <= 20) { if (doc.ingredients) { for (i=0; i < doc.ingredients.length; i++) { for (j=0; j < doc.ingredients.length; j++) { emit([doc.ingredients[i].ingredient, doc.ingredients[j].ingredient], null); } } } } }
すると、両方の食材の明示的なクエリを実行できます:
?key=["carrot","rice"]
柔軟な調理時間を本当にサポートしたい場合、調理時間を追加することもできます:
function(doc, meta) { if (doc.ingredients) { for (i=0; i < doc.ingredients.length; i++) { for (j=0; j < doc.ingredients.length; j++) { emit([doc.ingredients[i].ingredient, doc.ingredients[j].ingredient, recipe.totaltime], null); } } } }
すると、調理時間内で2つの食材の選択を使った範囲のクエリをサポートできます:
?startkey=["carrot","rice",0]&key=["carrot","rice",20]
これは以下と同じです:
SELECT recipeid FROM recipe JOIN ingredients on ingredients.recipeid = recipe.recipeid WHERE (ingredient = 'carrot' OR ingredient = 'rice') AND totaltime = 20