コンテンツへスキップ

Webブラウザ上で使えるデータベース、IndexedDBを使ってみよう

by : 2018/06/06

Webブラウザ上でデータを保存しておくための仕組みは幾つか用意されています。

  • Cookies
  • localStorage/sessionStorage
  • IndexedDB
  • Web SQL

昔から使われているのはCookiesですが、長い文字列を保存するのには向いていません。一般的に4096バイトくらいまでとなっています。localStorageはそれよりも大きいですが、10MBくらいまでになります(localStorageは恒久、sessionStorageはセッション中のみ保存されます)。Web SQLはSQLが使える高度なデータベース機能ですが、実装がSQLiteを前提としていることで、中立性に欠けるという声もあり、開発は停止しています(via HTML5 – Web SQLデータベース)。現在は IndexedDBの利用が推奨されています。

今回は IndexedDB の使い方について紹介します。

IndexedDB の概要

IndexedDBはlocalStorageなどと同じく、キーバリュー型のストレージになります。localStorageは文字列しか保存できないのでJSONなどを保存しようと思った場合には文字列に変換する必要がありますが、 IndexedDBはJSONのまま保存できます。かといって一般的なデータベースのように検索を行える訳ではありません。

localStorageは同期型で、getItem/setItemを実行できましたが、IndexedDBは非同期型の技術になっています。また、オブジェクト(テーブル相当)をあらかじめ定義しておく必要があり、構造をバージョンという形で管理します。構造を作る際にはユニーク指定も可能です。オブジェクトの構造は自由に変えられますが、キーは定義しておく必要があります。

DBを開く

まず最初にデータベースを開きます。この時、バージョン番号を指定します(整数のみ)。このバージョン番号があがると onupgradeneeded が呼ばれますので、この際にスキーマを変更します。通常時は onsuccess が呼ばれます。


let db;
let version = 1;
const request = indexedDB.open("database", version);
request.onerror = function(event) {
alert("IndexedDB が使えません");
};
request.onupgradeneeded = function(event) {
db = event.target.result;
const objectStore = db.createObjectStore("items", { keyPath: "id" });
objectStore.createIndex("name", "name", { unique: false });
objectStore.createIndex("description", "description", { unique: true });
};
request.onsuccess = function(event) {
db = event.target.result;
}

view raw

index.js

hosted with ❤ by GitHub

データの追加

データを追加する際には、オブジェクトストア(テーブル相当)を指定して readwrite でトランザクションを作成します。そしてオブジェクトストアに対して add を実行します。各データ追加時に onsuccess が呼ばれますが、すべての処理が完了した際には oncomplete が呼ばれます。


const transaction = db.transaction(["items"], "readwrite");
transaction.oncomplete = function(event) {
console.log("完了しました");
};
transaction.onerror = function(event) {
console.log("エラーです", event);
};
const objItem = transaction.objectStore("items");
for (let i = 1; i < 10; i += 1) {
objItem.add(
{id: i, name: `テスト商品 ${i}`, description: `テスト商品 ${i} の説明`, add: '追加'}
).onsuccess = function (event) {
console.log(event.target.result);
}
}

view raw

index.js

hosted with ❤ by GitHub

データの取得

データの取得は get を使います。この際には書き込みは発生しませんのでトランザクションはオブジェクトストアを指定するだけで使えます。


db.transaction(["items"])
.objectStore("items")
.get(3)
.onsuccess = function(event) {
console.log("取得しました", event.target.result);
}

view raw

index.js

hosted with ❤ by GitHub

データの更新

データの更新を行う際にはトランザクションを readwrite で作成します。そして取得したデータに対して put を使って更新します。


const Items = db.transaction(["items"], "readwrite").objectStore("items");
Items.get(3)
.onsuccess = function(event) {
const row = event.target.result;
row.name = "商品3の名前を変更";
Items
.put(row)
.onsuccess = function(event) {
console.log("更新しました");
}
}

view raw

index.js

hosted with ❤ by GitHub

データの削除

データの削除はdeleteメソッドに対してキーを指定するだけです。


db.transaction(["items"], "readwrite")
.objectStore("items")
.delete(2)
.onsuccess = function(event) {
console.log("削除完了しました");
}

view raw

index.js

hosted with ❤ by GitHub

まとめ

IndexedDB をそのまま使おうとすると若干の癖があります。作成、更新はオブジェクトストアが必須ですが、取得や削除は不要という処理の違いも面倒だったり、トランザクションの作成も手間に感じます。ラッピングしてくれるORM的なライブラリを使って操作するのが良さそうです。

IndexedDB 自体はlocalStorage以上に便利に使えそうなので、ぜひ活用してみてください。

Can I use… Support tables for HTML5, CSS3, etc

From → HTML5

コメントは受け付けていません。