Webブラウザ上で使えるデータベース、IndexedDBを使ってみよう
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
が呼ばれます。
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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; | |
} |
データの追加
データを追加する際には、オブジェクトストア(テーブル相当)を指定して readwrite でトランザクションを作成します。そしてオブジェクトストアに対して add を実行します。各データ追加時に onsuccess が呼ばれますが、すべての処理が完了した際には oncomplete が呼ばれます。
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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); | |
} | |
} |
データの取得
データの取得は get
を使います。この際には書き込みは発生しませんのでトランザクションはオブジェクトストアを指定するだけで使えます。
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
db.transaction(["items"]) | |
.objectStore("items") | |
.get(3) | |
.onsuccess = function(event) { | |
console.log("取得しました", event.target.result); | |
} |
データの更新
データの更新を行う際にはトランザクションを readwrite で作成します。そして取得したデータに対して put を使って更新します。
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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("更新しました"); | |
} | |
} |
データの削除
データの削除はdeleteメソッドに対してキーを指定するだけです。
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
db.transaction(["items"], "readwrite") | |
.objectStore("items") | |
.delete(2) | |
.onsuccess = function(event) { | |
console.log("削除完了しました"); | |
} |
まとめ
IndexedDB をそのまま使おうとすると若干の癖があります。作成、更新はオブジェクトストアが必須ですが、取得や削除は不要という処理の違いも面倒だったり、トランザクションの作成も手間に感じます。ラッピングしてくれるORM的なライブラリを使って操作するのが良さそうです。
IndexedDB 自体はlocalStorage以上に便利に使えそうなので、ぜひ活用してみてください。
コメントは受け付けていません。