blog

インデックスDB入門ガイド

html 5では、Indexed DBが使えるようになったことが大きな特徴です。この記事では、Indexed DBについて簡単に紹介します。...

Dec 18, 2013 · 47 min. read
シェア

html 5の興味深い新機能の一つは、インデックス付きDBが使えるようになったことです。 インデックス付きDB標準については、こちらのリンクから詳しく知ることができます。この記事では、Indexed DBについて簡単に紹介します。

中抜き

基本的に、IndexedDB を使用することで、ユーザーはブラウザに大量のデータを保存することができます。大量のデータを送信する必要があるアプリケーションであれば、ユーザーのブラウザ側にデータを保存することができるため、この機能の恩恵を受けることができます。現在、これは IndexedDB の機能の一つに過ぎず、ユーザーが必要とするデータを取得するための強力なインデックスベースの検索 API 機能も提供しています。

IndexedDBは他のストレージ機構とどう違うのですか?

クッキーは、ブラウザ側にデータを保存するための最も一般的に使用されるメカニズムですが、保存できるデータのサイズには限界があり、プライバシーの問題もあります。また、クッキーはリクエストごとにデータを送受信するため、クライアント側のデータ保存の利点は全くありません。

ローカルストレージはHTML 5をよくサポートしていますが、提供できるストレージの総量という点ではまだ制限されています。ローカルストレージは実際には「検索API」を提供しておらず、ローカルに保存されたデータはキーと値のペアを介してのみアクセスされます。ローカルストレージは、ユーザー設定などのデータを保存する必要がある特定のシナリオに適していますが、IndexedDBは広告などのデータを保存するのに適しています。

Indexed DB をさらに探求する前に、主要なブラウザにおける Indexed DB の現在のサポート状況を見てみましょう。 IndexedDB は現在まだ w3c の提案仕様の候補であり、この時点では仕様はまだ満足のいくものですが、現在は開発者コミュニティからのフィードバックを求めています。仕様は、***確認段階に達する前に、w3cの勧告に応じて変更される可能性があります。一般的に、IndexedDB に対する現在のブラウザのサポートは比較的統一された方法で実装されていますが、開発者はこれに対する将来の更新や修正に注意する必要があります。

CanIUse.comのブラウザ別IndexedDBサポートに関するグラフを見ると、デスクトップ用ブラウザは現在IndexedDBをよくサポートしていますが、モバイル用ブラウザはあまりサポートしていないことがわかります:

Android版ChromeはIndexedDBをサポートしていますが、現在Androidデバイスでこのブラウザを使っている人はほとんどいません。モバイルブラウザのサポートがないからといって、使うべきではないということでしょうか?もちろんそんなことはありません!幸いなことに、開発者は継続的改善のコンセプトを理解しています。IndexedDB のような機能は、それをサポートしていないブラウザにも別の方法で追加することができます。ユーザーはラップライブラリを使用してモバイル WebSQL に変換することもできますし、単純にモバイルでローカルにデータを保存しないこともできます。個人的には、クライアントサイドで大量のデータをキャッシュできることは、モバイルサポートがないとしても、利用する上で重要な機能だと思います。

学習開始

まず第一に、IndexedDBを使用する前に、やるべきことは、IndexedDBをサポートするための現在のブラウザかどうかを確認することです、練習はちょうど次のコードを使用する必要が達成することができます:

document.addEventListener("DOMContentLoaded", function(){ 
  
    if("indexedDB" in window) { 
        console.log("YES!!! I CAN DO IT!!! WOOT!!!"); 
    } else { 
        console.log("I has a sad."); 
    } 
  
},false); 

上記のコードは、読み込み処理でDOMContentLoadedイベントを使用して、ウィンドウオブジェクト内のindexedDBの存在を判断することで、もちろん、次の処理で判断の最終結果を覚えておくために、より良い保存するには、次のコードを使用することができます:

var idbSupported = false; 
  
document.addEventListener("DOMContentLoaded", function(){ 
  
    if("indexedDB" in window) { 
        idbSupported = true; 
    } 
  
},false); 

運用データベース

ここでは、IndexedDB データベースの操作方法について説明します。IndexedDBの原理は、クッキーやローカルストレージの原理と同じで、IndexedDBは一意なDOMAINと関連付けられます。IndexedDBの原理はクッキーやローカルストレージと同じで、IndexedDBは一意なDOMAINに関連付けられます。例えば、foo.com に関連付けられた "Foo" という名前のデータベースは、goo.com が作成した同じ "Foo" という名前のデータベースと衝突することはありません。なぜなら、これらは異なるドメインに属し、互いにアクセスできないからです。

データベースを開くにはコマンドを実行します。基本的な使い方は、データベースの名前とバージョン番号を指定することです。以下に基本的な例を示します:

var openRequest = indexedDB.open("test",1); 

IndexedDB データベースを開くのは非同期操作です。操作の戻り結果を処理するために、リッスンするイベントを追加する必要があります:

  • success
  • error
  • upgradeneeded
  • blocked

SUCCESSイベントとERRORイベントが何を意味するかはもうお分かりかと思います。また、upgradeneededイベントは、****がデータベースを開いたり、データベースのバージョンを変更したときに発生します。blockedイベントは、以前の接続が閉じられていないときに発生します。

次の例では、***がサイトを訪れたときにupgradeeneededイベントが発生し、その後にsuccessイベントが発生します。

var idbSupported = false; 
var db; 
  
document.addEventListener("DOMContentLoaded", function(){ 
  
    if("indexedDB" in window) { 
        idbSupported = true; 
    } 
  
    if(idbSupported) { 
        var openRequest = indexedDB.open("test",1); 
  
        openRequest.onupgradeneeded = function(e) { 
            console.log("Upgrading..."); 
        } 
  
        openRequest.onsuccess = function(e) { 
            console.log("Success!"); 
            db = e.target.result; 
        } 
  
        openRequest.onerror = function(e) { 
            console.log("Error"); 
            console.dir(e); 
        } 
  
    } 
  
},false); 

#p#

上記のコードでは、もう一度、現在のブラウザが IndexedDB に対応しているかどうかをチェックし、対応していればデータベースを開きます。このコードでは、アップグレードイベント、成功イベント、エラーイベントの3つのイベントが使用されています。まず成功イベントですが、これは target.result によってハンドルが渡され、後でデータを追加するためにグローバル変数 db にコピーされます。IndexedDBをサポートするブラウザで上記のコードを実行すると、コンソールにUpgrading...とsuccessの出力が表示されるはずです。とsuccessが表示されますが、もう一度実行すると、successのメッセージしか表示されません。なぜなら、upgradeneedイベントは、***データベースを開くか、アップグレードするときにのみ呼び出されるからです。

オブジェクトストレージ

IndexedDBには「オブジェクトストレージ」という概念があります。

ユーザはこれをリレーショナルデータベースの典型的なテーブルと考えることができます。このオブジェクトにはもちろんデータが格納されていますが、キーパスやインデックスも格納されています。いわゆるキーパスは、ユーザのデータを一意に識別するもので、さまざまな形式で表現することができます。一方、インデックスについては後で説明します。

upgrademeededイベントの話を覚えていますか?upgradeneededイベントでのみオブジェクトを作成できることに注意することが重要です。現在のところ、デフォルトでは、ユーザ***がサイトにアクセスすると自動的にオブジェクトが作成されます。また、オブジェクトを変更する場合は、データのバージョンを更新する必要があり、そのためのコードを記述する必要があります:

var idbSupported = false; 
var db; 
  
document.addEventListener("DOMContentLoaded", function(){ 
  
    if("indexedDB" in window) { 
        idbSupported = true; 
    } 
  
    if(idbSupported) { 
        var openRequest = indexedDB.open("test_v2",1); 
  
        openRequest.onupgradeneeded = function(e) { 
            console.log("running onupgradeneeded"); 
            var thisDB = e.target.result; 
  
            if(!thisDB.objectStoreNames.contains("firstOS")) { 
                thisDB.createObjectStore("firstOS"); 
            } 
  
        } 
  
        openRequest.onsuccess = function(e) { 
            console.log("Success!"); 
            db = e.target.result; 
        } 
  
        openRequest.onerror = function(e) { 
            console.log("Error"); 
            console.dir(e); 
        } 
  
    } 
  
},false); 

上記のコードで、upgradeneededイベントを見ると、まず変数 thisDBを通して開いているデータベースを取得します。オブジェクトが既に存在するかどうかをチェックするにはcontainsメソッドを使用し、存在しない場合はcreateObjectStoreメソッドを使用して、それを作成することができます。

要約すると、ユーザーがウェブサイトを訪問したとき、ユーザーのブラウザがIndexedDBをサポートしていれば、最初にトリガーされるイベントはupgradeneededイベントであり、コードは "firstOS "オブジェクトがあるかどうかをチェックします。ユーザーが2度目にサイトを訪れたとき、データベースのバージョンはまだ***時と同じです。

別のオブジェクト・ストアを追加する必要がある場合は、バージョン番号を追加し、上記のcontains/ createObjectStoreセクションのコードを以下のようにコピーするだけです:

var openRequest = indexedDB.open("test_v2",2); 
  
openRequest.onupgradeneeded = function(e) { 
    console.log("running onupgradeneeded"); 
    var thisDB = e.target.result; 
  
    if(!thisDB.objectStoreNames.contains("firstOS")) { 
        thisDB.createObjectStore("firstOS"); 
    } 
  
    if(!thisDB.objectStoreNames.contains("secondOS")) { 
        thisDB.createObjectStore("secondOS"); 
    } 
  
} 

データの追加方法

以下でデータの追加を開始できます。従来のリレーショナルデータベースとは少し異なり、IndexedDBではオブジェクトを保存することができます。つまり、開発者はJavascriptオブジェクトを保存することもできます。トランザクションは2つのパラメータを持ち、1つは処理するテーブルの配列で、その要素はテーブルです。現在、トランザクションには読み取り専用と読み取り書きの2種類があります。データの追加は読み書き操作であり、コードは以下のようになります:

var transaction = db.transaction(["people"],"readwrite"); 

ここでは、読み取りと書き込み操作のためにストレージオブジェクトの人々を設定し、objectStoreを使用して、操作され、変数ストアに格納されるストレージオブジェクトを指定することが示されています。

var store = transaction.objectStore("people"); 

次にデータを追加し、人物オブジェクトを定義してこのストアに追加します:

var person = { 
    name:name, 
    email:email, 
    created:new Date() 
} 
  
var request = store.add(person,1); 

あなたが見ることができるように、ここでJavascriptの一般的なオブジェクトを宣言し、その後、ストアの追加メソッドを使用してオブジェクトをオブジェクトストアに追加するには、2番目のパラメータを追加するデータの一意の識別を識別することである、それは一時的にハードコードされ、次では、もはやハードコードされたメソッドで使用されません。

データを追加する操作は非同期なので、以下のコードで2つのイベント・リスナーを追加してください:

request.onerror = function(e) { 
    console.log("Error",e.target.error.name); 
    } 
  
request.onsuccess = function(e) { 
    console.log("Woot! Did it"); 
} 

test6.htmlを見てください。これがhtmlを含む完全なコードです:

<!doctype html> 
<html> 
<head> 
</head> 
  
<body> 
  
<script> 
var db; 
  
function indexedDBOk() { 
    return "indexedDB" in window; 
} 
  
document.addEventListener("DOMContentLoaded", function() { 
  
    //No support? Go in the corner and pout. 
    if(!indexedDBOk) return; 
  
    var openRequest = indexedDB.open("idarticle_people",1); 
  
    openRequest.onupgradeneeded = function(e) { 
        var thisDB = e.target.result; 
  
        if(!thisDB.objectStoreNames.contains("people")) { 
            thisDB.createObjectStore("people"); 
        } 
    } 
  
    openRequest.onsuccess = function(e) { 
        console.log("running onsuccess"); 
  
        db = e.target.result; 
  
        //Listen for add clicks 
        document.querySelector("#addButton").addEventListener("click", addPerson, false); 
    } 
  
    openRequest.onerror = function(e) { 
        //Do something for the error 
    } 
  
},false); 
  
function addPerson(e) { 
    var name = document.querySelector("#name").value; 
    var email = document.querySelector("#email").value; 
  
    console.log("About to add "+name+"/"+email); 
  
    var transaction = db.transaction(["people"],"readwrite"); 
    var store = transaction.objectStore("people"); 
  
        var person = { 
        name:name, 
        email:email, 
        created:new Date() 
    } 
  
        var request = store.add(person,1); 
  
    request.onerror = function(e) { 
        console.log("Error",e.target.error.name); 
        //some type of error handler 
    } 
  
    request.onsuccess = function(e) { 
        console.log("Woot! Did it"); 
    } 
} 
</script> 
  
<input type="text" id="name" placeholder="Name"><br/> 
<input type="email" id="email" placeholder="Email"><br/> 
<button id="addButton">Add Data</button> 
  
</body> 
</html> 

#p#

ブラウザでこのコードを実行すると、HTMLページの次の図を見ることができますテキストボックスにコンテンツを入力し、ボタンをクリックすると、ブラウザのデバッグツールで、次の出力が表示されます:

.Chromeを使用している場合、デバッグツールでIndexedDBのビジュアルサポートをフルに活用することができます。 ResourcesのTABをタップし、IndexedDBのセクションを展開すると、以下のように作成されたpeopleストレージオブジェクトを見ることができます。

このメッセージは、すでに格納されているオブジェクトを追加しようとすると、データ制約に違反することを示しています:

キーについて

キーは IndexedDB の主キーです。従来のリレーショナルデータベースはキーを持たないことができましたが、 IndexedDB では複数の異なるタイプのキーを持つことができます。

***つ目の方法は、peopleの例のように、キーがデータ自体の属性に基づくキーパスを使用する方法です。つ目の方法は、keypathを使う方法で、peopleの例のように、キーはデータ自体の属性に基づいています。1つはキーパスを使ったもの、もう1つはキージェネレータを使ったものです:

hisDb.createObjectStore("test", { keyPath: "email" });   
thisDb.createObjectStore("test2", { autoIncrement: true }); 

また、先ほどの例を修正して、キーを持つメソッドでオブジェクトを作成することもできます:

thisDB.createObjectStore("people", {autoIncrement:true}); 

その場合、ハードコーディングは不要になります:

var request = store.add(person); 

データを取り出す

データの読み方、トランザクション内のデータの読み方、非同期のデータの読み方を確認するために、以下に例を示します:

var transaction = db.transaction(["test"], "readonly"); 
var objectStore = transaction.objectStore("test"); 
  
var ob = objectStore.get(x); 
  
ob.onsuccess = function(e) { 
  
} 

上記のコードでは、まずトランザクションを読み取り専用に設定します。その後、objectStore.getメソッドを使用し、onsuccessイベントを記述します:

db.transaction(["test"], "readonly").objectStore("test").get(X).onsuccess = function(e) {} 

さて、test8.htmlに、例のデータを読み込む部分を追加すると、実行後の効果は以下のようになります:

データを読み取るコードの場所:

function getPerson(e) { 
    var key = document.querySelector("#key").value; 
    if(key === "" || isNaN(key)) return; 
  
    var transaction = db.transaction(["people"],"readonly"); 
    var store = transaction.objectStore("people"); 
  
    var request = store.get(Number(key)); 
  
    request.onsuccess = function(e) { 
  
        var result = e.target.result; 
        console.dir(result); 
        if(result) { 
            var s = "<h2>Key "+key+"</h2><p>"; 
            for(var field in result) { 
                s+= field+"="+result[field]+"<br/>"; 
            } 
            document.querySelector("#status").innerHTML = s; 
        } else { 
            document.querySelector("#status").innerHTML = "<h2>No match</h2>"; 
        }    
    }    
} 

#p#

より多くのデータを読む方法

どのようにバルクデータを読み取るには?IndexedDBは、データベースの基本的な知識を持っている読者のために理解しやすいカーソルの概念をサポートし、次のコードは、データセットを読み取る方法を示しています:

var transaction = db.transaction(["test"], "readonly"); 
var objectStore = transaction.objectStore("test"); 
  
var cursor = objectStore.openCursor(); 
  
cursor.onsuccess = function(e) { 
    var res = e.target.result; 
    if(res) { 
        console.log("Key", res.key); 
        console.dir("Data", res.value); 
        res.continue(); 
    } 
} 

objectStoreのopenCursorを使用してカーソルを開き、onsuccessイベント処理では、resを使用して結果セットを取得し、res.continue()メソッドを使用してレコードセットを循環させることに注意してください。同様に、ピープルストアのセットをトラバースするには、このメソッドを使用して、コードは次のとおりです:

function getPeople(e) { 
     var s = ""; 
  
    db.transaction(["people"], "readonly").objectStore("people").openCursor().onsuccess = function(e) { 
        var cursor = e.target.result; 
        if(cursor) { 
            s += "<h2>Key "+cursor.key+"</h2><p>"; 
            for(var field in cursor.value) { 
                s+= field+"="+cursor.value[field]+"<br/>"; 
            } 
            s+="</p>"; 
            cursor.continue(); 
        } 
        document.querySelector("#status2").innerHTML = s; 
    } 
} 

あなたはtest9.htmlで完全なコードを見ることができます、あなたは、人事情報を追加し続けることができますし、すべての情報を取得するポイント、次の図は、効果を実行します:

IndexedDB におけるインデックス

このチュートリアルの***では、IndexedDBの最も重要な部分であるインデックスについて説明します。まずインデックスの作成方法ですが、これはアップグレードイベントで行う必要があります:

var objectStore = thisDb.createObjectStore("people",  
                { autoIncrement:true }); 
objectStore.createIndex("name","name", {unique:false}); 
objectStore.createIndex("email","email", {unique:true}); 

この場合、***パラメータはインデックスの名前で、2番目のパラメータはカラムです。そして、カラムが一意であるかどうかを指定するには unique を使用します。

では、インデックスをどのように使うのでしょうか?トランザクションでオブジェクトストアを取得したら、インデックスを経由してデータを取得することができます:

var transaction = db.transaction(["people"],"readonly"); 
var store = transaction.objectStore("people"); 
var index = store.index("name"); 
  
var request = index.get(name); 
request.onsuccess = function(e) { 
  
    var result = e.target.result; 
    if(result) { 
        var s = "<h2>Name "+name+"</h2><p>"; 
        for(var field in result) { 
            s+= field+"="+result[field]+"<br/>"; 
        } 
        document.querySelector("#status").innerHTML = s; 
    } else { 
        document.querySelector("#status").innerHTML = "<h2>No match</h2>"; 
    }    
} 

次に、Rangeの別のインデックスベースの使用を見て、Rangeを介して、すべての名前の間の文字a〜文字cのようなデータ間のデータの特定の範囲を取得することができますが、また、境界を含めるかどうかを設定することができます含めることはできませんし、データの範囲間でソートすることができます、例を参照してください:

//39より大きい 
var oldRange = IDBKeyRange.lowerBound(39); 
  
//40を超える 
 var oldRange2 = IDBKeyRange.lowerBound(40,true); 
  
//39未満 
var youngRange = IDBKeyRange.upperBound(40); 
  
//39未満 
var youngRange2 = IDBKeyRange.upperBound(39,true); 
  
//2040の間 
var okRange = IDBKeyRange.bound(20,40) 

ここでは、IDBKeyRange というトップ・レベルのオブジェクトが使用され、lowerBound メソッドでは返されるデータが指定されたパラメータより大きいことを指定し、upperBound ではその逆が真となり、bound では指定された範囲の間のデータが返されます。検索の例を以下に示します。検索名の開始範囲と終了範囲は、ページ・フォームに以下のように入力します:

Starting with: <input type="text" id="nameSearch" placeholder="Name"><br/> 
Ending with: <input type="text" id="nameSearchEnd" placeholder="Name"><br/> 

イベントコードは

function getPeople(e) { 
    var name = document.querySelector("#nameSearch").value; 
  
    var endname = document.querySelector("#nameSearchEnd").value; 
  
    if(name == "" &amp;&amp; endname == "") return; 
  
    var transaction = db.transaction(["people"],"readonly"); 
    var store = transaction.objectStore("people"); 
    var index = store.index("name"); 
  
    
    if(name != "" &amp;&amp; endname != "") { 
        range = IDBKeyRange.bound(name, endname); 
    } else if(name == "") { 
        range = IDBKeyRange.upperBound(endname); 
    } else { 
        range = IDBKeyRange.lowerBound(name); 
    } 
  
    var s = ""; 
  
    index.openCursor(range).onsuccess = function(e) { 
        var cursor = e.target.result; 
        if(cursor) { 
            s += "<h2>Key "+cursor.key+"</h2><p>"; 
            for(var field in cursor.value) { 
                s+= field+"="+cursor.value[field]+"<br/>"; 
            } 
            s+="</p>"; 
            cursor.continue(); 
        } 
        document.querySelector("#status").innerHTML = s; 
    } 
  
} 

上記のコードでは、最初のエンドのユーザーを決定するために、テキストボックスは、検索条件を入力し、次に範囲に判断の組み合わせの条件を通じて、その上でカーソルindex.openCursor(範囲)を開くには、メソッドに渡された範囲は、IndexedDBは自動的に条件を満たすレコードを取得され、コードの例です。のコード例です。

チュートリアルの第2部では、更新、削除、配列などの操作について説明します。

この記事のコードのダウンロードは以下をご覧ください:/--db

Read next

オレンジ、次世代データセンターを建設

Orangeは、フランスのヴォードルイユに16,000 m²のデータセンターを建設し、Orangeの法人顧客と一般消費者にサービスを提供するとともに、Orangeのクラウドコンピューティングサービスの開発を加速し、グループ自身のIT変革を支援しています。

Dec 18, 2013 · 1 min read