前回からのつづき

前回、IndexedDBのオブジェクトを中心にAPIの説明を行ってきましたが、今回は、その続きとなります。

検索の要となる IDBKeyRangeオブジェクトの使い方を中心に、検索方法ついて説明します。


IDBKeyRangeとは?

IndexedDBの検索を支える超重要API

■ 結論(最初にここだけ読めばOK)

IDBKeyRange は 👉 **「どのデータを取得するかを決める条件オブジェクト」**です。

SQLでいうと:

WHERE 条件

に相当します。


IDBKeyRangeとは何か?

IndexedDBにはSQLのような検索構文がありません。

その代わりに使うのが:

  • IDBKeyRange(検索条件)
  • Index(検索対象)
  • Cursor(走査)

👉 この3つの組み合わせで検索を実現します


使い方(基本)

例えば「キーが10〜20のデータを取得」:

store.getAll(IDBKeyRange.bound(10, 20));


IDBKeyRangeの作り方(4種類)

① only(一致検索)

IDBKeyRange.only(value)

例:

IDBKeyRange.only(5)

👉 キーが5のデータだけ取得

② lowerBound(下限)

IDBKeyRange.lowerBound(value, open)

例:

IDBKeyRange.lowerBound(10)

👉 10以上

open の意味

  • false(デフォルト) → 10以上(>=)
  • true → 10より大きい(>)

③ upperBound(上限)

IDBKeyRange.upperBound(value, open)

👉 value以下

④ bound(範囲検索)

IDBKeyRange.bound(lower, upper, lowerOpen, upperOpen)

👉 最もよく使う

例:

IDBKeyRange.bound(10, 20)

👉 10以上20以下

図で理解する

only(5)
→ [5]

lowerBound(10)
→ [10 -------->

upperBound(20)
→ <-------- 20]

bound(10,20)
→ [10 ----- 20]


どこで使うのか?

① get / getAll

store.getAll(IDBKeyRange.bound(10, 20));

② Cursor(本命)

store.openCursor(IDBKeyRange.lowerBound(100));

👉 100以上だけ順に処理

③ Indexと組み合わせ

store.index("age")
     .openCursor(IDBKeyRange.bound(20, 30));

👉 年齢20〜30のデータだけ取得


実務でよく使うパターン

① ページング処理

IDBKeyRange.lowerBound(lastKey, true)

👉 前回の続きから取得

② 日付範囲検索

IDBKeyRange.bound(
  new Date("2024-01-01"),
  new Date("2024-12-31")
)

③ 前方一致検索(テクニック)

IDBKeyRange.bound("abc", "abc\uffff")

👉 "abc〜" で始まるデータ


なぜ重要なのか?

👉 IndexedDBにはWHERE句がない

SQLのように:

SELECT * WHERE age > 20

とは書けません。

👉 代わりにこうする

store.index("age")
     .openCursor(IDBKeyRange.lowerBound(20));

👉 必要なデータ("age"が20以上のもの)だけ取得できる


よくあるNG例

❌ 全件取得してフィルタ

// 非効率(絶対NGに近い)
const all = await store.getAll();
const result = all.filter(x => x.age > 20);

👉 大量データで詰む

✔ 正しいやり方

store.index("age")
     .openCursor(IDBKeyRange.lowerBound(20));

👉 取得する対照データを絞り込む


注意点(ハマりやすい)

❗ キーにしか使えない

👉 valueの中身では検索できない → Indexが必要

❗ 型が一致していないとヒットしない

"10" !== 10

❗ 無効な値はエラー

IDBKeyRange.only(undefined) // NG


IDBKeyRangeの内部動作(少しだけ)

実は内部では:

👉 IndexedDBのキー比較ルールで判定されています

イメージ:

cmp(key, lower) >= 0 && cmp(key, upper) <= 0


まとめ

✔ IDBKeyRangeとは

👉 「どのキーを対象にするか決める条件オブジェクト」

✔ よく使うもの

  • only(一致)
  • bound(範囲)
  • lowerBound(ページング)

✔ 本質

👉 IndexedDBの検索そのもの。一言でいうと「IndexedDBのWHERE句」

ここを理解すると、IndexedDBが「使いにくい」から 👉「自由に扱えるDB」に変わります 👍

(つづく)