前回からのつづき

前回、検索の要となる IDBKeyRangeオブジェクトの使い方を説明しましたが、今回は、その続きとなります。

データの取得において、判断に迷う getAll()とcursorについて、その判断基準と注意点について説明します。


【実務で迷わない】IndexedDBの getAll() vs cursor 徹底比較

結論

  • 少量データ → getAll() でOK(シンプル)
  • 大量データ → cursor 一択(安全・高性能)
  • ページング・無限スクロール → cursor 必須

👉 迷ったら「データ量」で判断するのが実務的。


getAll() の特徴

const request = store.getAll(null, 100)

✔ メリット

  • シンプルで書きやすい
  • 一括で配列として取得できる
  • 非同期処理が少なくて済む

❌ デメリット

  • 一気にメモリへ読み込む
  • データが多いとフリーズの原因
  • 途中から取得(ページング)ができない

向いているケース

  • 設定データ(数十件)
  • マスタデータ(数百件まで)
  • 初期表示で全部必要な場合

cursor の特徴

const request = store.openCursor()

request.onsuccess = (event) => {
  const cursor = event.target.result
  if (cursor) {
    console.log(cursor.value)
    cursor.continue()
  }
}

✔ メリット

  • 1件ずつ処理できる(メモリに優しい)
  • 大量データでも安全
  • 途中停止・再開ができる
  • ページング実装が可能

❌ デメリット

  • コードが少し複雑
  • 非同期処理が増える
  • 配列としてまとめる場合は自前処理が必要

向いているケース

  • ログデータ
  • 大量レコード(数千〜)
  • 無限スクロール
  • バックグラウンド処理

実務での使い分け

観点 getAll() cursor
実装の簡単さ
パフォーマンス △(大量で危険)
メモリ効率
ページング
小規模データ
大規模データ

👉 getAll()の使用は簡易的、基本的には、cursor を使用する。


よくある事故パターン

store.getAll()

👉 データが増えた瞬間に…

  • メモリ使用量急増
  • UIフリーズ
  • 最悪クラッシュ

👉 最初は問題なくても、運用後に壊れるのが怖い。


実務でのおすすめパターン

  • 安全な上限付き取得
store.getAll(null, 100)

👉 小〜中規模ならこれでOK。

  • 本番向け(安全設計)
const results = []

store.openCursor().onsuccess = (e) => {
  const cursor = e.target.result
  if (!cursor) return

  results.push(cursor.value)

  if (results.length < 100) {
    cursor.continue()
  }
}

👉 自前で「最大件数」を制御。

さらに実務っぽい話

なぜ cursor が重要なのか?

👉 IndexedDBは「ローカルDB」。

つまり:

  • ユーザー環境によってデータ量が読めない
  • 数万件になることも普通にある

👉 安全側に倒す設計が必要


まとめ

  • getAll() は便利だが、大量データに弱い
  • cursor は面倒だが、安全で拡張性が高い

実務では「最初から cursor 前提」で設計する方が事故が少ない。

一言アドバイス(差別化ポイント)

👉 「最初は getAll → 後で cursor に書き換え」では遅い。

最初から:

  • データ増加を前提に設計する
  • cursorベースで組む

👉 これだけで「壊れないアプリ」になります。