Practice of Programming

プログラム とか Linuxとかの話題

IndexedDB の onupgradeneeded の実装例

最近、ブラウザに内蔵されているローカル用のDBのIndexedDBを使ってみました。

developer.mozilla.org

DBのスキーマを変更したいようなときに、onupgradeneeded を使いますが、ちょっとした説明と実装例を示します。

なお、動作確認したブラウザは、Chrome 102 です。

IndexedDBでは、DBを開くときにバージョンを渡す

下記の、1というのがバージョンです。

DBOpenRequest = window.indexedDB.open("Sample", 1);

DBがないか、バージョンが変わった場合に呼ばれる upgradeneeded

もともと、バージョンを持っていない場合、もしくは、ブラウザが保持しているバージョンがopenで指定されているものより低い場合に、 upgradeneeded というイベントが呼ばれます。addEventListenerで定義するか、onupgradeneeded に代入するかで実装できます。

下記のように、定義します。

DBOpenRequest.addEventListener("onversionchanged", event => {});
DBOpenRequest.onupgradeneeded = event => {};

event の中身

下記くらい知っていれば良いのではないでしょうか。

key value
event.oldversion ブラウザが保持しているバージョン(なければ 0)
event.newVersion openに書かれているバージョン
event.target.result IDBDatabaseオブジェクト
event.target.transaction onupgrade中のトランザクション

のようなものがあります。

event.oldversionevent.newversion の差分を確認して、必要な変更を当てる必要があります。

実装例

下記のように各バージョンごとに関数定義すると良いのではないかなと思います。

        DBOpenRequest.onupgradeneeded = event => {
            const oldVersion = event.oldVersion;
            const newVersion = event.newVersion;;
            const db = event.target.result;
            const migration = {
                "1": () => {
                    { // User master
                        const s = db.createObjectStore('user', {keyPath: "nickname"});
                        s.createIndex("nickname", "nickname", {unique: true});
                    }
                    { // logs
                        const s = db.createObjectStore("logs", {keyPath: "date"});
                        s.createIndex("date", "date", {unique: false});
                        s.createIndex("content", "content", {unique: false});
                    }
                },
                "2": () => {
                    { // logs (date => loggedDate に変えたくなった)
                        db.deleteObjectStore("logs");  // 消して作り直してます。中身とって、入れ直しとかしたら良いですね。
                        const s = db.createObjectStore("logs", {keyPath: "date"});
                        s.createIndex("loggedDate", "date", {unique: false});
                        s.createIndex("content", "content", {unique: false});
                    }
                },
                "3": () => {
                    { // logs (titleいるよね)
                        const s = event.target.transaction.objectStore("logs"); // transaction からとってこないとエラーになります
                        s.createIndex("title", "title", {unique: false});
                    }               
                }
            }

           // 最新バージョンになるまで差分を適用
            for (let v = oldVersion + 1; v <= newVersion; v++) {
                if (migration[v]) {
                    migration[v]();
                }
            }
        };

versionchange イベント

これは、試せてないのですが、別のタブとかで開いているときに、片方でDBのバージョンアップが走った場合に、起きるイベントのようです。 勝手にアップデートされる前に、DBに保存すると行った処理を実装するために使うようです。

例として、A, B のタブでSampleというDBを使っている。

そのときに、A で、upgradeが走るときに、B にversionchange イベントが発生するようです。

下記に詳しく載っています。

www.w3.org