HTML5 - Indexed Database API

目次

Indexed Database APIとは

Indexed Database API は、Cookie, Web Storage, Web SQLデータベース と同様、アプリケーションデータをクライアント側に保存する仕組みのひとつです。下記の仕様が公開されています。

Cookie や Web Storage が Key-Value形式、Web SQLデータベースが SQL をサポートするのに対し、Indexed Database API では、SQLに依存しない NoSQL に分類される方法でデータにアクセスします。

Web SQLデータベースに代わり、今後の標準となる予定ですが、まだ仕様は確定しておらず、各ブラウザの実装にも非互換性がずいぶんあるようです。

Indexed Database API は、下記のブラウザで部分的にサポートが始まっています。

サンプル

サンプルでは、DBの作成、データの追加、データの1件参照、データの全件参照、DBの削除を実装しています。Firefox 12, Chrome 19 で、動作を確認しています。

HTML
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Indexed Database API Sample</title>
<style>
#message {
    margin: 1em;
    padding: 1em;
    border: 1px solid gray;
    font: 9pt Courier;
    white-space: pre;
}
</style>
<script>
var ver = 201205201;
var indexedDB = window.indexedDB || window.webkitIndexedDB || window.mozIndexedDB;
var IDBTransaction = window.IDBTransaction || window.webkitIDBTransaction || window.mozIDBTransaction;
var db = null;

function print(msg) {
    document.getElementById("message").innerHTML += msg + "\n";
}

function clearConsole() {
    document.getElementById("message").innerHTML = "";
}

function createSample() {
    print("----------------------------------------------------");
    print("START: createSample()");
    var reqOpen = indexedDB.open("sampleDB", ver);

    reqOpen.onupgradeneeded = function(e) {
        print("START: reqOpen.onupgradeneeded()");
        db = reqOpen.result;
        db.createObjectStore("sample", { "keyPath": "id" });
        print("EXEC : createObjectStore()");
        print("END  : reqOpen.onupgradeneeded()");
    }
    reqOpen.onsuccess = function(e) {
        print("START: reqOpen.onsuccess()");
        db = reqOpen.result;
        if (db.setVersion) {
            var reqVersion = db.setVersion(ver);
            reqVersion.onsuccess = function() {
                print("START: reqVersion.onsuccess()");
                db.createObjectStore("sample", { "keyPath": "id" });
                print("EXEC : createObjectStore()");
                print("END  : reqVersion.onsuccess()");
            }
        }
        print("END  : reqOpen.onsuccess()");
    }
    reqOpen.onerror = function(err) { print("ERROR: " + err.code + ":" + err.message); }
    reqOpen.onblocked = function(err) { print("INFO : BLOCKED"); }
    print("END  : createSample()");
}

function addSample() {
    print("----------------------------------------------------");
    print("START: addSample()");
    var userList = [
        { "id": 1, "name": "Yamada", "age": 18, "addr": "Tokyo" },
        { "id": 2, "name": "Suzuki", "age": 27, "addr": "Osaka" },
        { "id": 3, "name": "Tanaka", "age": 36, "addr": "Kyoto" },
        { "id": 4, "name": "Kimura", "age": 45, "addr": "Aichi" }
    ];

    var transaction = db.transaction(["sample"], IDBTransaction.READ_WRITE);
    var store = transaction.objectStore("sample");
    for (var i = 0; i < userList.length; i++) {
        var data = userList[i];
        var reqAdd = store.add(data);
        print("EXEC : add() " + data.id + " / " + data.name + " / " + data.age + " / " + data.addr);
        reqAdd.onsuccess = function(e) { print("INFO : add() -> SUCCESS"); }
        reqAdd.onerror = function(e) { print("INFO : add() -> ERROR"); }
    }
    print("END  : addSample()");
}

function getSample() {
    print("----------------------------------------------------");
    print("START: getSample()");
    var transaction = db.transaction(["sample"], IDBTransaction.READ_ONLY);
    var reqGet = transaction.objectStore("sample").get(1);
    print("EXEC : get()");
    reqGet.onsuccess = function(e) {
        var data = reqGet.result;
        print("DATA : " + data.id + " / " + data.name + " / " + data.age + " / " + data.addr);
    }
    reqGet.onerror = function(e) { print("ERROR: add() -> " + e); }
    print("END  : getSample()");
}

function getAllSample() {
    print("----------------------------------------------------");
    print("START: getAllSample()");
    var transaction = db.transaction(["sample"], IDBTransaction.READ_ONLY);
    var reqGet = transaction.objectStore("sample").openCursor();
    print("EXEC : openCursor()");
    reqGet.onsuccess = function(e) {
        var cursor = reqGet.result;
        var data = cursor.value;
        print("DATA : " + cursor.key + " / " + data.name + " / " + data.age + " / " + data.addr);
        cursor.continue();
    }
    reqGet.onerror = function(e) { print("ERROR: add() -> " + e); }
    print("END  : getAllSample()");
}

function deleteSample() {
    print("----------------------------------------------------");
    print("START: deleteSample()");
    if (db) { db.close(); }
    var reqDelete = indexedDB.deleteDatabase("sampleDB");
    print("EXEC : deleteDatabase()");
    reqDelete.onsuccess = function(e) { print("INFO : deleteDatabase() -> SUCCESS"); }
    reqDelete.onerror = function(e) { print("ERROR: deleteDatabase() -> " + e); }
    reqDelete.onblocked = function(e) { print("INFO : BLOCKED"); }
    print("END  : deleteSample()");
}
</script>
</head>
<body>
<button onclick="createSample()">CREATE</button>
<button onclick="addSample()">ADD</button>
<button onclick="getSample()">GET</button>
<button onclick="getAllSample()">GET ALL</button>
<button onclick="deleteSample()">DELETE</button>
<button onclick="clearConsole()">CLEAR</button>
<div id="message"></div>
</body>
</html>

API

API利用の準備

まだ仕様が確定していないため、Firefox では mozIndexedDB, Chrome では webkitIndexedDB として実装しています。

JavaScript
var indexedDB = window.indexedDB || window.webkitIndexedDB || window.mozIndexedDB;
var IDBTransaction = window.IDBTransaction || window.webkitIDBTransaction || window.mozIDBTransaction;

データベースを開く

まず、データベースを開きます。第一引数にはデータベース名を指定します。第二引数は、2010年8月の仕様ではDBの説明を指定していました。2011年4月の仕様では第二引数は廃止されました。最新の 2011年12月の仕様では、第二引数は unsigned long long 型のバージョン(省略可能)を指定します。

JavaScript
reqOpen = indexedDB.open("sampleDB", 20120520);

データストアを作成する

Firefox 12 の実装では、reqOpen.onupgradeneeded イベントハンドラで createObjectStore() を呼び出します。Chrome 19 の実装では、reqOpen.onsuccess イベントハンドラで db.setVersion() を呼び出し、その reqVersion.onsuccess イベントハンドラで createObjectStore() を呼び出します。createObjectStore() の第一引数にはオブジェクトストア名を、第二引数にはキー名などを指定します。

JavaScript
// Firefox 12
reqOpen.onupgradeneeded = function(e) {
    db = reqOpen.result;
    db.createObjectStore("sample", { "keyPath": "id" });
}
// Chrome 19
reqOpen.onsuccess = function(e) {
    db = reqOpen.result;
    var reqVersion = db.setVersion(ver);
    reqVersion.onsuccess = function() {
        db.createObjectStore("sample", { "keyPath": "id" });
    }
}

データを追加する

db.transaction() でトランザクションを生成し、transaction.objectStore() でオブジェクトストアを得た後、add() でデータを追加します。成功時には onsuccess, 失敗時には onerror イベントが発生します。

JavaScript
var data = { "id": 1, "name": "Yamada", "age": 18, "addr": "Tokyo" };
var transaction = db.transaction(["sample"], IDBTransaction.READ_WRITE);
var store = transaction.objectStore("sample");
var reqAdd = store.add(data);
reqAdd.onsuccess = function(e) { ... };
reqAdd.onerror = function(e) { ... };

データを検索する

データを検索するには get() を用います。引数にはキー値を指定します。結果は onsuccess ハンドラで参照します。

JavaScript
var transaction = db.transaction(["sample"], IDBTransaction.READ_ONLY);
var store = transaction.objectStore("sample");
var reqGet = store.get(1);
reqGet.onsuccess = function(e) {
    var data = reqGet.result;
    print("DATA : " + data.id + " / " + data.name + " / " + data.age + " / " + data.addr);
}

データの一覧を得る

データの一覧を得るには openCursor() を使用します。古い仕様では getAll() メソッドが用意されていましたが、廃止されました。

JavaScript
var transaction = db.transaction(["sample"], IDBTransaction.READ_ONLY);
var store = transaction.objectStore("sample");
var reqGet = store.openCursor();
reqGet.onsuccess = function(e) {
    var cursor = reqGet.result;
    var key = cursor.key;
    var value = cursor.value;
    print("DATA : " + key + " / " + value.name + " / " + value.age + " / " + value.addr);
    cursor.continue();
}

データベースを削除する

データベースを削除するには deleteDatabase() を用います。

JavaScript
var reqDelete = indexedDB.deleteDatabase("sampleDB");
reqDelete.onsuccess = function(e) { ... };
reqDelete.onerror = function(e) { ... };
reqDelete.onblocked = function(e) { ... };