LoginSignup
6
3

More than 5 years have passed since last update.

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

Last updated at Posted at 2018-03-16

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"から始まる項目を取得することができます。

6
3
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
6
3