HTML5 - Indexed Database API
Indexed Database APIとは
Indexed Database API は、Cookie, Web Storage, Web SQLデータベース と同様、アプリケーションデータをクライアント側に保存する仕組みのひとつです。下記の仕様が公開されています。
- 最新版: https://www.w3.org/TR/IndexedDB-2/
- V2.0: https://www.w3.org/TR/2017/PR-IndexedDB-2-20171116/ [PR]
- V1.0: https://www.w3.org/TR/2015/REC-IndexedDB-20150108/ [REC]
Cookie や Web Storage が Key-Value形式、Web SQLデータベースが SQL をサポートするのに対し、Indexed Database API では、SQLに依存しない NoSQL に分類される方法でデータにアクセスします。
Web SQLデータベースに代わり、今後の標準となる予定ですが、まだ仕様は確定しておらず、各ブラウザの実装にも非互換性がずいぶんあるようです。
Indexed Database API は、下記のブラウザで部分的にサポートが始まっています。
- Internet Explorer 10(β版)
- Firefox 4.0
- Google Chrome 11
サンプル
サンプルでは、DBの作成、データの追加、データの1件参照、データの全件参照、DBの削除を実装しています。Firefox 12, Chrome 19 で、動作を確認しています。
<!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 として実装しています。
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 型のバージョン(省略可能)を指定します。
reqOpen = indexedDB.open("sampleDB", 20120520);
データストアを作成する
Firefox 12 の実装では、reqOpen.onupgradeneeded イベントハンドラで createObjectStore() を呼び出します。Chrome 19 の実装では、reqOpen.onsuccess イベントハンドラで db.setVersion() を呼び出し、その reqVersion.onsuccess イベントハンドラで createObjectStore() を呼び出します。createObjectStore() の第一引数にはオブジェクトストア名を、第二引数にはキー名などを指定します。
// 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 イベントが発生します。
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 ハンドラで参照します。
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() メソッドが用意されていましたが、廃止されました。
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() を用います。
var reqDelete = indexedDB.deleteDatabase("sampleDB");
reqDelete.onsuccess = function(e) { ... };
reqDelete.onerror = function(e) { ... };
reqDelete.onblocked = function(e) { ... };