IndexedDBにはまってます。(その21)

まず最初に、インデックスキー(補キー)によるレコードの格納(putとaddメソッド)はありません。プライマリキー(主キー)の指定がないのですから、当たりまえっちゃー当たりまえです。

そして今回は、カーソルは後回しなので使いません。そして削除のメソッドもありません。(なんと!)

getgetKeyメソッド、getAllgetAllKeyメソッド、countメソッドによるレコードの参照だけになります。(注意:これらはIDBIndex のインスタンスメソッドです。)プライマリキー(主キー)によるIndexedDBにはまってます。(その13)(その14)の投稿と比較すると良いでしょう。

申し上げた通り、参照しかしませんからトランザクション発動モードは「readonly」一択です。

今回もコピペコード全てをテキストファイル「code_IndexedDB_21.txt.zip」にまとめてアップロードしました。ご利用ください。

説明の都合上、今回はつぎの登録用配列を利用します。Webブラウザ(Google Chromeを利用)のコンソールにコピー&ペーストし、エンターキーで登録します。

コピペコードファイルの「登録用インデックスキー(補キー)の配列」です。

const storeIndex = [
	{name:'indexEn', path:'index.en', unique:false, multi:false},
	{name:'indexSn', path:'index.sn', unique:false, multi:false},
	{name:'indexArray', path:['index.en','id'], unique:false, me:false}
];

(その19)にあった通り、オブジェエクストア生成とインデックスキー(補キー)を登録したら、(その14)と同様にレコードの格納まで済ませます。

コピペコードファイルの「オブジェクトストア生成と共にインデックスキー(補キー)登録」の実行につづいて、「レコードの配列」を登録し、「レコードの格納」を実行します。

オブジェクトストアに格納されたレコード

まずは素直にメソッドの利用方法だけを見ていきます。(その13)と(その14)にならってcountメソッドから紹介します。

その前に、忘れずに、コピペコードファイルの「ラングオブジェクトを生成するメソッド」を登録します。

説明は後にして、つぎのコードをWebブラウザのコンソールにコピー&ペーストし、エンターキーで実行します。

コピペコードファイルの「countメソッド(その1:’indexEn’)」です。

const openRequest = indexedDB.open('DB_name');
openRequest.addEventListener('success', (event)=>{
	const db = event.target.result;
	console.log(`データベースを開始しました。`);
	if(db.objectStoreNames.contains('Store_name')) {
		const tx = db.transaction('Store_name', 'readonly');
		tx.addEventListener('complete', (event)=>{console.log(`トランザクションが完遂しました。`);}, false);
		tx.addEventListener('error', (event)=>{console.error(`トランザクションでエラーが発生しました。`);}, false);
		tx.addEventListener('abort', (event)=>{console.error(`トランザクションが中断しました。`);}, false);
		const objectStore = tx.objectStore('Store_name');
		//任意のインデックスキー(補キー)をパラメータにインデックスオブジェクトを取得する。
		let indexObject = null;
		try {
			indexObject = objectStore.index('indexEn');
		} catch(e) {
			console.error(`例外が発生しました。_>${exception.message}`);
		}
		if(indexObject !== null) {
			//ラングオブジェクト生成
			const range = newRange({start:{v:2, b:false}, end:{v:5, b:false}});
			try {
				//レコード操作箇所
				const indexRequest = indexObject.count(range);
				indexRequest.addEventListener('success', (event)=>{
					console.log(`ストア内操作に成功しました。_>>> ${event.target.result}`);
					console.dir(event.target.result);
				}, false);	
				indexRequest.addEventListener('error', (event)=>{console.error(`ストア内操作に失敗しました。`);}, false);
			} catch(exception) {
				console.error(`例外が発生しました。_>${exception.message}`);
			}
		}
	} else console.error(`目的のオブジェクトストアはありませんでした。`);
	db.close();
	db.addEventListener('close', ()=>{console.log(`データベースが閉鎖されました。`);}, false);
}, false);
openRequest.addEventListener('error', (event)=>{console.error(`データベースの開始に失敗しました。`);}, false);
コンソール画面の入力と結果表示

コンソールに「ストア内操作に成功しました。_>>> 4」と出力されました。

コードを確認してください。「//任意のインデックスキー(補キー)をパラメータにインデックスオブジェクトを取得する。」までは(その13)のcountメソッドのものと同じです。

定数objectStoreを取得した後で、さらにそこからindexメソッドでインデックスオブジェクトを取得します。(ここはじっくりと確認しましょう。)その際、例外が発生する可能性がありますからtry文で包みます。

プライマリキー(主キー)だとそのまま行っちゃいますが、インデックスキー(補キー)ではさらに一段掘り下げます。

indexメソッドのパラメータはインデックスキー(補キー)の名前です。ここでは「indexEn」です。パスは「index.en」でプライマリキー(主キー)の片割れです。

Google Chromeのアプリケーション画面でインデックスキー(補キー)「indexEn」の項目をアクティブにすると、ちゃんと当該キーの並びを確認できます。(便利ですねー。感謝。)

アプリケーション画面の「indexEn」項目

そして(その13)同様に、ラングオブジェクトを生成して、countメソッドのパラメータとすれば、その領域のレコード数が返ってきます。

もちろん、try文の中でこの操作を続けても大丈夫です。でも、入れ子になるのを嫌う私は、先に変数indexObjectを宣言しておき、インデックスオブジェクトの取得があったのを確認した後で操作する記述をしてます。

さてここで少し余計なことをしてみます。

indexメソッドのパラメータを「indexArray」に変更します。

indexObject = objectStore.index('indexArray');

同じく、アプリケーション画面でインデックスキー(補キー)「indexArray」の項目をアクティブにして当該キーの並びを確認します。

アプリケーション画面の「indexArray」項目

その並びを見ながら、ラングオブジェクトを生成するnewRangeメソッドのパラメータを、つぎのように配列に変更します。

コピペコードファイルの「countメソッド(その2:’indexArray’)」と同じコードを実行します。

const range = newRange({start:{v:[4,7], b:false}, end:{v:[6,3], b:false}});
コンソール画面の入力と結果表示

コンソールに「ストア内操作に成功しました。_>>> 3」と出力されました。確かに該当範囲内にレコードは三つあります。

もう一つ、余計なことをします。

実は、countメソッドのパラメータにラングオブジェクトだけでなく、キーの値を利用できます。

試しにcountメソッドのパラメータを「range」から「[1,2]」とします。

アプリケーション画面のインデックスキー(補キー)「indexArray」項目に配列[1,2]があるのを確認できると思います。

コピペコードファイルの「countメソッド(その3:’indexArray’)」と同じコードを実行します。

const indexRequest = indexObject.count([1,2]);
コンソール画面の入力と結果表示

コンソールに「ストア内操作に成功しました。_>>> 1」と出力されました。

あるんだから「当たり前じゃん。」と思われたかもしれません。

でも、インデックスキー(補キー)の指定次第でレコードの有無確認に利用できると期待できます。

ところで、(その13)では触れなかったのですが、プライマリキー(主キー)においても同様にパラメータを指定できます。

もとより一意のプライマリキー(主キー)においては、あまり有効性を感じていなかったので端折っていました。先に「もう一つ、余計なことをします。実は、…」と記述した次第です。

getAllとgetAllKeysメソッドの紹介に移ります。

indexメソッドのパラメータは「indexArray」のまま、newRangeメソッドのパラメータもそのままで進めます。

countメソッドをgetAllメソッドに差し替えて、コピペコードファイルの「getAllメソッド」と同じものを実行します。

const indexRequest = indexObject.getAll(range);
コンソール画面の入力と結果表示

レコードが三つ取得できました。

つづけてgetAllメソッドをgetAllKeysメソッドに差し替えて、コピペコードファイルの「getAllKeysメソッド(その1)」と同じものを実行します。

const indexRequest = indexObject.getAllKeys(range);
コンソール画面の入力と結果表示

返り値にて取得できたのは、三つのプライマリキー(主キー)です。インデックスキー(補キー)の取得も可能とは思いますが、素直に返ってくるのはこちらでした。

さてここでまた余計なことをしてみます。

getAllとgetAllKeysメソッドでは、整数の第二パラメータが指定できます。

つぎのように記述して、コピペコードファイルの「getAllKeysメソッド(その2)」と同じものを実行します。

const indexRequest = indexObject. getAllKeys(range, 2);
コンソール画面の入力と結果表示

先頭から二つのプライマリキー(主キー)が取得できたと思います。getAllメソッドも同じく、第二パラメータが指定できます。

やはり、(その13)では触れませんでしたがプライマリキー(主キー)でも利用できます。これこそ利用の可能性が予想でませんでした(いまでも)ので端折りました。

つぎはgetとgetKeyメソッドです。おなじくcountメソッドに替えます。

プライマリキー(主キー)の場合と同じで、最初のひとつのレコードしか返してくれません。

そして(重要)ラングオブジェクトしかパラメータにできません。プライマリキー(主キー)ではcountメソッドの様にキーの値を指定できましたが、ここではラングオブジェクトの一択です。

そして(さらに重要)パラメータのラングオブジェクトがnullだとエラーになります。「なんで一番最初のレコードを返してくれないの?」と叫び声をあげたい!この仕様のために余計な網を張らなくてはなりませんて…。

ここで重要な閑話です。

前述の「ラングオブジェクトがnullだとエラーに」ですが、プライマリキー(主キー)のgetgetKeydeleteメソッド(注意:これらはIDBObjectStoreのインスタンスメソッドです。)でも同じでした

「get(null)」とか「get()」にして実行すると例外が発生します。(注意:現在MDNの解説には齟齬があります。)

さらに、(その13)では流れで説明しているので記憶にないかもしれませんが、プライマリキー(主キー)のcountgetAllgetAllKeyメソッド(注意:これらはIDBObjectStoreのインスタンスメソッドです。)でも、インデックスキー(補キー)のcountとgetAll、getAllKeyメソッド(注意:これらはIDBIndex のインスタンスメソッドです。)でも、「ラングオブジェクトがnullだと」全レコードが対象になります。

「count(null)」とか「count()」にして実行すると全レコード数が取得できます。

(ふー。何もかも漏れなくとは行きませんね。ごちゃごちゃだけども…。)

閑話休題。

つぎのように記述して、コピペコードファイルの「getメソッド」と同じものを実行します。

const indexRequest = indexObject.get(range);
コンソール画面の入力と結果表示

同じく、getKeyメソッドもつぎのように記述して、コピペコードファイルの「getKeyメソッド」と同じものを実行します。

const indexRequest = indexObject.getKey(range);
コンソール画面の入力と結果表示

返ってくるのはgetAllKeysメソッドと同じくプライマリキー(主キー)です。

おわたー。長くなりましたあ。(すみません。)

つぎはラスボスに挑む前に、且つ、少しシンプルなうちに、インデックスキー(補キー)登録の指定項目について、その実際を紹介します。

そのあと、カーソルボスのお出ましです。そかさ。