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

IndexedDBの学習成果を備忘するためにはじめた「はまってシリーズ」も6回目ですが、どう考えても、あと20回ぐらい(それでも終わらないかも…、)は続けないと終わりそうにありません。

いやいや、書籍一冊分になっちゃいそうで、ちょっと気が遠くなります。でも、お休みを入れながらも、気が済むまでは続けるだろうと予想してます。

IndexedDBにはまってます。(その5)では、プライマリキー(主キー)によるレコードをput()メソッドを利用して格納してみました。

「はじめてのレコード。」って感じでした。

今回は、もう一つあるadd()メソッドを利用して動作の比較をしてみます。そして複数のレコードでごちゃっとなったオブジェクトストアの中身を一掃するclear()メソッドの紹介もいたします。

まずは、ちゃちゃっとデータベースDB_nameを生成し、オブジェクトストアStore_nameをプライマリキー(主キー)’member’のキージェネレータをオンして生成します。

つぎのコードをWebブラウザ(Google Chromeを利用)のコンソールにコピー&ペーストし、エンターキーを押して実行します。

const openRequest = indexedDB.open('DB_name');
openRequest.addEventListener('upgradeneeded', (event) => {
	const db = event.target.result;
	//const tx = event.target.transaction;
	console.log(`UPGRADE_DB_VER_>${db.version}_OLD_>${event.oldVersion}_NEW_>${event.newVersion}`);
	const Store_option = {keyPath:'member', autoIncrement:true};
	const objectStore = db.createObjectStore('Store_name', Store_option);
	objectStore.transaction.addEventListener('complete', (event)=>{
		if(event.target.objectStoreNames.contains('Store_name')) {
			console.log(`オブジェクトストアを生成しました。`);
		}
	}, false);
	objectStore.transaction.addEventListener('abort', (event)=>{console.error(`トランザクションが中断しました。`);}, false);
	objectStore.transaction.addEventListener('error', (event)=>{console.error(`トランザクションでエラーが発生しました。`);}, false);

}, false);
openRequest.addEventListener('success', (event)=>{
	const db = event.target.result;
	console.log(`データベースを開きました。`);
	//db.close();
}, false);
openRequest.addEventListener('error', (event)=>{console.error(`データベースの開始が失敗しました。`);}, false);

オブジェクトストアが生成されました。

そして、データレコード(以下、レコードです。)をまずはput()メゾットを利用して格納します。

今回、成功(onsuccess)イベントを受けた「利用」処理では、オブジェクトストア名の一覧オブジェクト(DOMStringList)を参照し、オブジェクトストアStore_nameの有無を確認してから、トランザクションを発動(生成)してます。これがないと「そんなオブジェクトストアはないぞ!」とIndexedDB様から苦情が来てしまいます。

つぎのようにデータベースのobjectStoreNames(DOMStringList)オブジェクトのcontains()メソッドを参照し、パラメータにオブジェクトストア名を入れると、オブジェクトストアの有無の真偽値が取得できます。

db.objectStoreNames.contains('Store_name')

例外の回避処理は随所にあるのですが、今回はこのくらいにしておきましょう。

そしたら、つぎのコードをWebブラウザのコンソールにコピー&ペーストし、エンターキーを推して実行します。

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', 'readwrite');
		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');
	
		const storeRequest = objectStore.put({index:{en:1, sn:'SN0003'}, date:Date.now(), title:'ZINC', author:'hustlemouse', tag:['red','blue','yellow'], note:'Zn', member:2});
		
		storeRequest.addEventListener('success', (event)=>{console.log(`レコードの書き込みに成功しました。`);}, false);	
		storeRequest.addEventListener('error', (event)=>{console.error(`レコードの書き込みに失敗しました。`);}, false);
	} else console.error(`目的のオブジェクトストアはありませんでした。`);
	//db.close();
}, false);
openRequest.addEventListener('error', (event)=>{console.error(`データベースの開始が失敗しました。`);}, false);

つぎのようにコンソールに出力があり、レコードが格納されます。

データベースを開きました。
レコードの書き込みに成功しました。
トランザクションが完遂しました。
アプリケーション画面に現れたレコード

したらば、同じコードをコピー&ペーストし、レコードデータの「author:’hustlemouse’」を例えば「author:’頑張る亜鉛ちゃん’」と、つぎのように変更して実行します。

(キーボードの上矢印カーソルキーを押すと、直前に実行したコードが現れます。ご存知かと思いますが、老婆心まで。)

const storeRequest = objectStore.put({index:{en:1, sn:'SN0003'}, date:Date.now(), title:'ZINC', author:'頑張る亜鉛ちゃん', tag:['red','blue','yellow'], note:'Zn', member:2});
コンソールでレコードを格納した実行画面

つぎのようにコンソールに出力があり、レコードが変更されたように見えます。

データベースを開きました。
レコードの書き込みに成功しました。
トランザクションが完遂しました。
アプリケーション画面の変更されたレコード

再度、同じコードをコピー&ペーストし、レコードデータの「author:’頑張る亜鉛ちゃん’」を(例えば)元の「author:’hustlemouse’」に戻します。(上矢印カーソルキーを2回押してもいいです。)

そして今度は、put()ではなくadd()を使って変更してみます。putの部分をaddに変更して、て実行します。

「add」にするのをお忘れなく。

const storeRequest = objectStore.add({index:{en:1, sn:'SN0003'}, date:Date.now(), title:'ZINC', author:'hustlemouse', tag:['red','blue','yellow'], note:'Zn', member:2});
add()メソッドでレコードを格納した実行画面

つぎのようにコンソールに出力があり、失敗します。

データベースを開きました。
レコードの書き込みを失敗しました。
トランザクションでエラーが発生しました。
トランザクションが中断しました。

失敗して中断しましたね。もちろん、レコードへの格納は実行されてません。

add()メソッドでレコードを登録しようとすると、プライマリキー(主キー)の値が同じであった場合はすでにあるレコードを尊重?して失敗してくれちゃうのです。

一方、put()メソッドは有ろうが無かろうが、強引にまるっと上書きをしてしまいます。変更箇所を見つけて更新するなんて気の利いたことはしません。

add()で操作ができなかったので、試しに該当レコードを削除してからadd()してみましょう。

レコードの削除にはdelete()メソッドを利用します。ここではパラメータにプライマリキー(主キー)の値(ここでは数値、2になってますよね?)を指定するだけです。

const storeRequest = objectStore.delete(2);

操作手続きはput()やadd()のと同じです。put()やadd()の行をdelete()の行に差し替えるだけです。

削除するということは操作になりますから、transaction()で発動(生成)されるトランザクションは書き込み可能(readwrite)モードです。

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', 'readwrite');
		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');
	
		const storeRequest = objectStore. delete(2);
		
		storeRequest.addEventListener('success', (event)=>{console.log(`レコードの削除に成功しました。`);}, false);	
		storeRequest.addEventListener('error', (event)=>{console.error(`レコードの削除に失敗しました。`);}, false);
	} else console.error(`目的のオブジェクトストアはありませんでした。`);
	//db.close();
}, false);
openRequest.addEventListener('error', (event)=>{console.error(`データベースの開始が失敗しました。`);}, false);
コンソールでレコードを削除した実行画面

つぎのようにコンソールに出力があり、レコードを削除します。

データベースを開きました。
レコードの削除に成功しました。
トランザクションが完遂しました。
アプリケーション画面からレコードが消失

もう一度add()メソッドによるレコード格納を実行します。レコードが一個もないので、当たり前に感じると思いますが、格納されます。

add()メソッドでレコードを格納した実行画面
アプリケーション画面に現れたレコード

さらにもう一度add()メソッドを実行してみてください。やっぱりエラーになると思います。

そしたら、試しにレコードのデータオブジェクトの「member:2」を「member:3」と、プライマリキー(主キー)に当たる値を変更し、実行してみます。

プライマリキー(主キー)の値が異なるので新しいレコードとして格納されるはずです。

アプリケーション画面に現れた「member:3」のレコード

確認が済みましたら、データベースを削除しておきましょう。

本投稿では、レコードの格納と削除の基本動作を紹介しました。

(その7)では、キージェネレータのオンとオフにおけるput()やadd()の動作とclear()を紹介できるのではないかと思います。

キージェネレータのオンオフによる特性について、自分でも解っているのか少々不安です。まあでも学習しながら進めます。ここは、ほころびの出ないうちに投稿を締めます。そかさ。