IndexedDBでインデックスを利用して前方一致検索する

IndexedDBでは,インデックスを利用してデータベースから項目を検索することが出来ます。
完全一致で検索する処理は容易に実装が可能ですが,前方一致で検索したい場合にはひと工夫が必要です。

ひとことで言うと

インデックスに対するカーソルの範囲をこうすれば良い。

const str = 'hoge';
const nextStr = str.slice(0, -1) + String.fromCharCode(str.slice(-1).charCodeAt() + 1);

const range = IDBKeyRange.bound(str, nextStr, false, true);

//~~~~

index.openCursor(range);
//'hoge'から始まる項目にマッチ

下ごしらえ

こんな感じでデータベースdataを初期化。
idをキーパスとして使用し,nameで検索するためのインデックスを作成しています。
なお,例外処理や非同期処理の処理順などについては省略しています。

init
let DB;

const init= () =>{
  const request = window.indexedDB.open('data', 1);

  request.onupgradeneeded = e => {
    const db = request.result;
    const store = db.createObjectStore('data', {keyPath: 'id'});

    //'name'で検索するためのインデックスを作成
    store.createIndex('name', 'name');
  }

  request.onsuccess= e => {
    DB = request.result;
  }
}

init();

このデータベースに対し,次のデータを追加します。

add
const add= data => {
  const db = DB;
  const transaction = db.transaction('data', 'readwrite');
  const store = transaction.objectStore('data');

  store.put(data);
}

const data=[
  {id: '0', name: 'hoge'},
  {id: '1', name: 'fuga'},
  {id: '2', name: 'hogehoge'}
];

add(data[0]);
add(data[1]);
add(data[2]);

範囲を指定してnameインデックスから項目を取得する関数を定義。

search
const search= range => {
  const db = DB;
  const transaction = db.transaction('data', 'readonly');
  const store = transaction.objectStore('data');
  const request = store.index('name').openCursor(range, 'next');

  request.onsuccess= e => {
    const cursor = request.result;
    if (cursor){
      console.log('検索結果:', cursor.value);
      cursor.continue();
    } else {
      console.log('検索終了');
    }
  }
}

name"hoge"に完全一致するデータを取得するにはこんな感じ。

完全一致
const range= IDBKeyRange.only("hoge");
search(range);

// 検索結果:{id: '0', name: 'hoge'}
// 検索終了

本題

name"hoge"から始まるデータを取得するにはこうします。

前方一致
const str = 'hoge';
const nextStr = str.slice(0, -1) + String.fromCharCode(str.slice(-1).charCodeAt() + 1);

const range = IDBKeyRange.bound(str, nextStr, false, true);
search(range);

// 検索結果:{id: '0', name:'hoge'}
// 検索結果:{id: '2', name:'hogehoge'}
// 検索終了

nextStrは,strの最後の一文字を「文字コードにおける次の文字」に置き換えた文字列です。この場合は"hogf"になります。
IDBKeyRange.bound(str, nextStr, false, true)は,strからnextStrの範囲(ただしnextStrを含まない)を指定しています。

すなわち,nameを辞書順に並べたときに"hoge""hoge"より後ろかつ"hogf"より前にある文字列にマッチするので,"hoge"から始まる項目を取得することができます。

Sign up for free and join this conversation.
Sign Up
If you already have a Qiita account log in.