【ルービックキューブのタイマーを作る】第5回 IndexedDBを使ってみる回

もうシリーズも今回で5回目。今回は、テスト的にIndexedDBを使ってみようと思う。個人的に使ったことがないので。テスト回なのでソースコードは微妙なところが多々ありますが、お許しください。
IndexedDBとは
IndexedDBは、ブラウザ内にデータを保存する機能。永続的保存です。CookieやlocalStorageは、容量の問題で却下。サーバー側のRDBを利用する事も考えたが、複数人で利用する場合にはユーザー管理が必要になるので、いまいち。そこで、IndexedDBを採用することにする。
IndexedDBは利用できる容量が桁違いに多いので問題なく、ブラウザで管理される事によりこちらでユーザー管理を考える必要もない。
基本の使い方は?
さて、IndexedDBはまったく利用したことがないので、そのあたりからお勉強である。
IndexedDB API – Web API | MDNを見て、学ぶ。
const DB_NAME = 'cube'; const DB_VERSION = 3; const storeName = 'data'; let db; let objStore; const request = window.indexedDB.open(DB_NAME, DB_VERSION); // open失敗 request.onerror = (event) => { window.alert('データの保存に失敗しました'); }; request.onsuccess = (event) => { db = event.target.result; }; request.onupgradeneeded = (event) => { db = event.target.result; objStore = db.createObjectStore(storeName, {keyPath: 'name'}); const data = {name:'dataset1', date: 1741489549, scramble: 'B D\' B2 R D2 R D\' B L2 F2 U2 D\' B2 L2 U\' B2 D B2 U\' R', time: 41581}; objStore.add(data); };
ちょっと正しい使い方かはさておき、データを追加することには成功しました。Chromeのデベロッパーツールで見てみたのがこちら。

配列をそのままつっこんでみる
いろいろドキュメントを眺めてみると、基本的にはKVS的な使い方が一般的なのかなと感じ取れた。
と同時に、某有名サービスでこういう使い方をしているみたいなので、同様にやってみた。キーを指定して全データが入った配列を取得するような使い方だ。
const DB_NAME = 'cube'; const DB_VERSION = 3; const storeName = 'data'; let db; let objStore; const request = window.indexedDB.open(DB_NAME, DB_VERSION); // open失敗 request.onerror = (event) => { window.alert('データの保存に失敗しました'); }; request.onsuccess = (event) => { db = event.target.result; }; request.onupgradeneeded = (event) => { db = event.target.result; objStore = db.createObjectStore(storeName); const data = [ { name: 'dataset1', date: 1741489549, scramble: 'B D\' B2 R D2 R D\' B L2 F2 U2 D\' B2 L2 U\' B2 D B2 U\' R', time: 41581 }, { name: 'dataset1', date: 1741489549, scramble: 'B D\' B2 R D2 R D\' B L2 F2 U2 D\' B2 L2 U\' B2 D B2 U\' R', time: 41581 }, { name: 'dataset1', date: 1741489549, scramble: 'B D\' B2 R D2 R D\' B L2 F2 U2 D\' B2 L2 U\' B2 D B2 U\' R', time: 41581 } ]; objStore.add(data, 'dataset1'); };
こうすると、データはどうなるか。

無事配列データが入っていますね。こうしておくと、データセットを分けて保存したい場合、キーを変更して保存するということになる。
やっぱり1件ずつデータ登録したい気がする
しかしまぁ・・・本来の目的を考えると、1件ずつ別データとして保存しておくのがきれいな形な気はするので、トライする。
const DB_NAME = 'cube'; const DB_VERSION = 3; const storeName = 'data'; let db; let objStore; const request = indexedDB.open(DB_NAME, DB_VERSION); // open失敗 request.onerror = (event) => { window.alert('データの保存に失敗しました'); }; request.onsuccess = (event) => { db = request.result; }; request.onupgradeneeded = (event) => { db = request.result; objStore = db.createObjectStore(storeName, {keyPath: "id", autoIncrement: true}); const datasetIndex = objStore.createIndex("by_dataset", "dataset"); const data = [ { dataset: 1, time: 41581, scramble: 'B D\' B2 R D2 R D\' B L2 F2 U2 D\' B2 L2 U\' B2 D B2 U\' R', date: 1741489549, }, { dataset: 2, time: 39581, scramble: 'B D\' B2 R D2 R D\' B L2 F2 U2 D\' B2 L2 U\' B2 D B2 U\' R', date: 1741499549, }, { dataset: 1, time: 65581, scramble: 'B D\' B2 R D2 R D\' B L2 F2 U2 D\' B2 L2 U\' B2 D B2 U\' R', date: 1741519549, } ]; objStore.put(data[0]); objStore.put(data[1]); objStore.put(data[2]); };

こうしておいて、dataset=1のみ取得して使うことが出来れば良い。
const DB_NAME = 'cube'; const DB_VERSION = 3; const storeName = 'data'; let db; let objStore; let items = []; const request = indexedDB.open(DB_NAME, DB_VERSION); // open失敗 request.onerror = (event) => { window.alert('データの保存に失敗しました'); }; request.onsuccess = (event) => { db = request.result; }; request.onupgradeneeded = (event) => { db = request.result; objStore = db.createObjectStore(storeName, {keyPath: "id", autoIncrement: true}); const datasetIndex = objStore.createIndex("by_dataset", "dataset"); const data = [ { dataset: 1, time: 41581, scramble: 'B D\' B2 R D2 R D\' B L2 F2 U2 D\' B2 L2 U\' B2 D B2 U\' R', date: 1741489549, }, { dataset: 2, time: 39581, scramble: 'B D\' B2 R D2 R D\' B L2 F2 U2 D\' B2 L2 U\' B2 D B2 U\' R', date: 1741499549, }, { dataset: 1, time: 65581, scramble: 'B D\' B2 R D2 R D\' B L2 F2 U2 D\' B2 L2 U\' B2 D B2 U\' R', date: 1741519549, } ]; objStore.put(data[0]); objStore.put(data[1]); objStore.put(data[2]); }; document.getElementById('scramble').addEventListener('click', function () { const tx = db.transaction(storeName, "readonly"); const store = tx.objectStore(storeName); const index = store.index("by_dataset"); const allResult = index.getAll(1); allResult.onsuccess = (event) => { items = event.target.result; }; }); document.getElementsByTagName('header')[0].addEventListener('click', function () { console.log(items); });
ちょっとソースコードはきたないんですが、許してくださいw無事に値は取得できました。なんとか使えそうな気がします。
まとめ
IndexedDBにデータを保存し、取得することが出来ました。使い方には少し癖があるので、やや大変でした。次回は、思考錯誤しながらですが、
今回のソースコード
本日の実装が完了した状態のタグが「v1.0.5」です。今回のファイルはテスト用ファイルなので、次回には削除していると思います。
https://github.com/supilog/cube/tree/v1.0.5
- app/Http/Controllers/CubesController.php
- resources/js/db.js
- resources/views/test01.blade.php