Webアプリケーションでデータを保存する方法はいくつかありますが、IndexedDBはその中でも特に高機能なものです。CookieやLocalStorageは比較的よく知られていますが、IndexedDBはそれらを凌ぐ機能を持っています。
今回は、このIndexedDBの基本的な使い方と活用方法について、初心者にも分かりやすく解説します。
IndexedDBとは
IndexedDBはその名の通り、データベースの一種です。Webブラウザ上で動作するデータベースで、データを保存・取得・削除ができます。IndexedDBは以下の特徴を持っています。
- キーと値のペアをデータを保存
- インデックスを作成して高速に検索
- トランザクションをサポートしてデータの整合性を保つ
- スキーマのバージョン管理ができる
- ほとんどの操作が非同期で行われる
IndexedDBは、キーバリューストア(KVS)という点ではLocalStorageと似ています。しかし、LocalStorageが文字列しか保存できないのに対し、IndexedDBは値がオブジェクトである点が大きな違いです。
IndexedDBの基本的な使い方
では、ここからIndexedDBの基本的な使い方を解説します。
データベースを開く
IndexedDBを使うためには、まずindexedDB.open()
メソッドを使ってデータベースを開きます。
const request = indexedDB.open("myDatabase", 1);
ここで、第1引数はデータベース名、第2引数はデータベースのバージョンです。
そして、データベースが開けたかどうかはコールバックで確認します。
// 成功の場合
request.onsuccess = function(event) {
const db = event.target.result;
console.log("データベースが開けました");
};
// エラーの場合
request.onerror = function(event) {
console.log("データベースが開けませんでした");
};
オブジェクトストアを定義
次に、データベースの中に、オブジェクトストア(テーブルのようなもの)を定義します。 keyPath
はプライマリキーを指定します。この処理は、 request.onupgradeneeded
の中で行います。
request.onupgradeneeded = function(event) {
const db = event.target.result;
const objectStore = db.createObjectStore("customers", { keyPath: "id" });
};
ここで、createObjectStore()メソッドの第1引数はオブジェクトストア名、第2引数はオプションです。keyPathはプライマリキーとなるプロパティ名を指定します。
オブジェクトストアにインデックスを定義することもできます。
objectStore.createIndex("name", "name", { unique: false });
request.onupgradeneeded
はバージョン番号が変化した際に呼び出されます。
データを追加する
オブジェクトストアにデータを追加するには、トランザクションを使います。例えば、以下のようなデータを追加してみましょう。
const customers = [
{
"id": 1,
"name": "Alice",
"age": 20
},
{
"id": 2,
"name": "Bob",
"age": 30
}
]
そして、トランザクションを使って、データを追加します。
transaction
メソッドの1つ目の引数はオブジェクトストアの名前(文字列、または配列)、2つ目の引数はモードです。読み書きする場合には readwrite
を指定しますが、取得だけの場合は省略可能です。
const customerObjectStore = db
.transaction("customers", "readwrite")
.objectStore("customers");
customerData.forEach((customer) => {
customerObjectStore.add(customer);
});
データを検索する
データを検索する場合もトランザクションを使います。
const transaction = db.transaction(["customers"]);
const objectStore = transaction.objectStore("customers");
const request = objectStore.get("1");
request.onerror = (event) => {
// エラー処理
};
request.onsuccess = (event) => {
console.log(ID for 2 is ${request.result.name}
);
};
ここでは、get()メソッドを使ってプライマリキーが"1"のデータを取得しています。
データを更新する
データを更新する場合には、 put
メソッドを使います。
const request = db
.transaction(["customers"], "readwrite")
.objectStore("customers")
.put({ id: 1, name: "Alice", age: 21 });
データを削除する
データを削除する場合も、トランザクションを開始し、オブジェクトストアにアクセスしてdelete()メソッドを使います。
const request = db
.transaction(["customers"], "readwrite")
.objectStore("customers")
.delete("1");
request.onsuccess = (event) => {
// 削除完了した時のコールバック
};
これがIndexedDBの基本的な使い方です。
IndexedDBの実用的な使い方
ラッパーライブラリを使ってシンプルに
IndexedDBは非同期処理が基本で、onsuccessなどのイベントハンドラを定義する必要があります。これは初心者にとって少し複雑に感じるかもしれません。現代的なJavaScriptでは、async/awaitやPromiseを使うのが一般的ですね。
そこでおすすめなのが、IndexedDBのラッパーライブラリを使うことです。特に「Dexie.js」は使いやすいライブラリで、シンプルなコードでIndexedDBを操作できます。
特に Dexie.js は使いやすいライブラリです。以下はそのコードです。
const db = new Dexie("MyDatabase");
// テーブルの定義(++id は自動採番)
db.version(1).stores({
friends: "++id, name, age"
});
// データの検索
const oldFriends = await db.friends
.where("age").above(75)
.toArray();
// データの追加
await db.friends.add({
name: "Camilla",
age: 25,
street: "East 13:th Street",
picture: await getBlob("camilla.png")
});
他にも「PouchDB」や「idb」など、便利なライブラリがあります。これらを使えば、IndexedDBをストレスなく使いこなせるでしょう。
オフラインアプリケーションを作ろう
IndexedDBの大きな魅力は、ブラウザ内で動作するため、ネットワーク接続が不要なことです。これを利用して、オフラインでも動作するアプリケーションを作ることができます。
例えば、クラウドサービスからデータをまとめてダウンロードし、実際の動作はIndexedDBで行うといった使い方ができます。この場合、クラウドとIndexedDBの同期処理と、フロントエンドとIndexedDBとで処理を分けることが重要です。それさえできれば、オフラインアプリケーションを作るのは難しくありません。
ネットワークとデータベースを切り離せると、万一クラウドサービスが落ちている際にも、アプリケーションは動作を続けられます。これは、ユーザーエクスペリエンスの向上につながります。
Web Workerと組み合わせて高速処理
IndexedDBは、Web Workerと組み合わせることで、さらに強力なツールになります。Web Workerはブラウザのバックグラウンドで動作するJavaScriptで、重い処理を担当させることができます。
例えば、フロントエンドで処理が必要なデータをIndexedDBに登録し、Web Workerを呼び出します。Web WorkerはIndexedDBのデータを参照・更新します。IndexedDBではバイナリファイルも扱えるので、画像の処理をWeb Workerで行うこともできます。
このように、IndexedDBとWeb Workerを組み合わせることで、アプリケーションのパフォーマンスを大幅に向上させることができるのです。
まとめ
IndexedDBは、Web開発者にとって非常に便利なツールです。ラッパーライブラリを使えばシンプルに、オフラインアプリケーションを作れば利便性が向上し、Web Workerと組み合わせれば高速処理が可能になります。ぜひ、IndexedDBを使いこなして、より良いアプリケーションを作ってみてください!