Mokelab Blog

#40 IndexedDBの使い方

ブラウザにはIndexedDBという、インデックス付きテーブルなデータベースが用意されています。 今回はこのIndexedDBの使い方を紹介してみます。

MDNの公式ドキュメントはこちらにあります。

データベースを開く

データベースを開くには、indexedDB.open()を使います。この関数はコールバックベースなので、次のようにPromise を返す関数でラップするとよいでしょう。

const openIndexedDB = (name, version, onupgradeneeded) =>
  new Promise((resolve, reject) => {
    // 開く
    const r = indexedDB.open(name, version);
    r.onupgradeneeded = (ev) => {
      const db = ev.target.result;
      onupgradeneeded(db);
    };
    // IDBDatabase型を結果として返す
    r.onsuccess = (ev) => resolve(ev.target.result);
    r.onerror = (ev) => reject(ev);
  });

onupgradeneeded()は初回のオープンや、バージョンが変わった時に呼ばれます。オブジェクトストア作成はここで行うとよいでしょう。

オブジェクトストアを作る

IndexedDBでは、テーブルに相当するものとしてオブジェクトストアがあります。データベースの初回オープン時に作成してしまいましょう。

// testというデータベースを開く
const db = await openIndexedDB("test", 1, (db) => {
  // オブジェクトストアを作る
  db.createObjectStore("myStore", { keyPath: "id" });
});

オブジェクトストアを作るには、createObjectStore()を呼びます。第1引数にはオブジェクトストア名を指定し、 第2引数には上記のようにキーとなるフィールド名を指定します。

データを追加する

データをオブジェクトストアに追加するには、次のようにput()を呼びます。このメソッドもコールバックベースになっているので、 Promiseでラップするのがよいでしょう。

const putData = (db, storeName, value) =>
  new Promise((resolve, reject) => {
    const tr = db.transaction([storeName], "readwrite");
    const store = tr.objectStore(storeName);
    // ここでデータを追加
    const request = store.put(value);

    tr.oncomplete = () => resolve();
    tr.onerror = (err) => reject(err);
  });

put()の場合、オブジェクトストアに同じキーのデータがあった場合は上書きになります。store.add(value) もあり、こちらは同じキーのデータがあった場合はエラー(Key already exists in the object store.)になります。

データを取得する

getAll()を呼ぶとオブジェクトストアに入っているデータ全部を取得し、 get(key)を呼ぶとキー指定で1件だけ取得します。

const getAll = (db, storeName) =>
  new Promise((resolve, reject) => {
    const tr = db.transaction([storeName]);
    const store = tr.objectStore(storeName);
    // 全件取得
    const request = store.getAll();

    request.onsuccess = (ev) => resolve(ev.target.result);
    request.onerror = (err) => reject(err);
  });

キー指定で1件だけ取得するラッパーです。

const getByKey = (db, storeName, key) =>
  new Promise((resolve, reject) => {
    const tr = db.transaction([storeName]);
    const store = tr.objectStore(storeName);
    const request = store.get(key);

    request.onsuccess = (ev) => resolve(ev.target.result);
    request.onerror = (err) => reject(err);
  });

まとめ

IndexedDBの基本的な使い方を紹介しました。ブラウザに大量のデータを保存させたい場合に役立つので、使えるようになっておきましょう。

本サイトではサービス向上のため、Google Analyticsを導入しています。分析にはCookieを利用しています。