IndexedDBでの検索がちょっと便利になるMultiEntry

HTML5 Advent Calendarの24日目です。
残すところあと1日となりました!
他の方々が有用な記事をたくさん書いて頂いているので、そちらも是非チェックしてみてください。

さて、私からはIndexedDBのMultiEntryという仕組みについて少しだけ解説したいと思います。
IndexedDBが題材ということで少しマニアックですが…


IndexedDBの検索方法
IndexedDBの検索方法について簡単に触れておくと、その名前の通り、あらかじめ索引を作成して検索するというものです。つまり、検索に使う可能性があるプロパティやパターンをあらかじめ洗い出しておく必要があります。また、RDBMSのように複合検索というものがないため、複雑な検索を行うためには、データ検索用のプロパティを別途用意しなければなりません。


検索がちょっと便利になるMultiEntry
前述したように、IndexedDBは複合検索が非常に面倒なのですが、MultiEntryという仕組みを利用すれば、ちょっとした複合検索ができます。
MultiEntryとは、索引を作成する際に複数のプロパティを指定する仕組みです。作成方法は簡単で、インデックスを作成する際のプロパティの指定をArrayで渡すだけです。

// インデックスを作成
store.createIndex('composite', ['flag', 'postDate'], { unique: false} );

// データ例:{id: 1, message: 'メッセージ1', flag: 0, postDate: new Date(2012,11,24) }


検索方法は、Rangeオブジェクトを作成する際にupperもしくはlowerなどに、同じようにArrayを渡して指定します。

// 検索条件:flag, postDate
var lower = [ 0, new Date(2012,11,1) ],
      upper = [ 0, new Date(2012,11,25) ] ;

// Rangeオブジェクト作成
var range = IDBKeyRange.bound(lower, upper);

// カーソル取得
var cursorReq = index.openCursor(range);


ここで注意して欲しいのは、例えばプロパティ1の検索条件で絞込み、更にプロパティ2で絞り込むというような形にはならないということです。サンプルの検索条件で言えば、flagで絞り込んだあとに、更にpostDateで絞り込んでいるように見えますが、正確には違います(それができるなら完全な複合検索ですね)。IndexedDBでは、あくまでflag+postDateでソートした結果を範囲検索しているだけです。よくわからないと思いますので、以下の図をみてください。


図: MultiEntryの検索範囲


つまり、flag+postDateでデータをソートし、そのデータの下限と上限をRangeのlowerとupperで指定するというものです。これが例えば、flag>postDateの順番が逆(postDate>flag)だと検索結果が違ってくることがわかるかと思います。


まとめ
今回は、IndexedDBのデータの持ち方を知っていないと、考え方がちょっと面倒なMultiEntryの仕組みを解説しました。MultiEntryは、複合検索する上で万能ではありませんが、ちょっとしたフラグ+プロパティ検索みたいなケースであれば簡単に利用することができるので、おすすめです。IndexedDBで複雑な検索をする場合は、選択肢のひとつとして覚えておくと良いかと思います。