環境構築からWEBアプリ開発・スマホアプリ開発まで。ときには動画制作やゲームも。

supilog
すぴろぐ

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

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

もうシリーズも今回で5回目。今回は、テスト的にIndexedDBを使ってみようと思う。個人的に使ったことがないので。テスト回なのでソースコードは微妙なところが多々ありますが、お許しください

IndexedDBとは

IndexedDBは、ブラウザ内にデータを保存する機能。永続的保存です。CookieやlocalStorageは、容量の問題で却下。サーバー側のRDBを利用する事も考えたが、複数人で利用する場合にはユーザー管理が必要になるので、いまいち。そこで、IndexedDBを採用することにする。

IndexedDBは利用できる容量が桁違いに多いので問題なく、ブラウザで管理される事によりこちらでユーザー管理を考える必要もない。

基本の使い方は?

さて、IndexedDBはまったく利用したことがないので、そのあたりからお勉強である。

IndexedDB API – Web API | MDNを見て、学ぶ。

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
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);
};
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); };
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的な使い方が一般的なのかなと感じ取れた。

と同時に、某有名サービスでこういう使い方をしているみたいなので、同様にやってみた。キーを指定して全データが入った配列を取得するような使い方だ。

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
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');
};
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'); };
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件ずつ別データとして保存しておくのがきれいな形な気はするので、トライする。

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
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]);
};
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]); };
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のみ取得して使うことが出来れば良い。

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
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);
});
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); });
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

リンク

「ルービックキューブのタイマーを作る」シリーズ