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

IndexedDBにはまってます。(その4)では、準備したオブジェクトストアを削除するところまで紹介しました。

いままでは、データベースのアップグレード(onupgradeneeded)イベント発火を受けた「準備」枠内の操作でしたが、今回はデータベースを開いた成功(onsuccess)イベント発火を受けた「利用」枠内の操作です。

はまってシリーズ初の「利用」枠の話題は、オブジェクトストアへのデータレコード(以下、レコードとします。)の格納です。

まずは、(その3)と同様にデータベースとその内部にオブジェクトストアを生成します。

オブジェクトストア生成につき、オプションにkeyPathを’member’、autoIncrementを真(true)として登録します。(この箇所が(その3)の実行コードと異なりますので注意してください。)

はまってシリーズで言うところの、プライマリキー(主キー)は’member’で、キージェネレータはオンということになります。

const Store_option = {keyPath:'member', autoIncrement:true};

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

定数txの行はそのうち使うので、コメントアウトして残してます。

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);
コンソールでオブジェクトストアを生成した実行画面

つぎのようにコンソールに出力があって、実行が終了します。

UPGRADE_DB_VER_>1_OLD_>0_NEW_>1
オブジェクトストアを生成しました。
データベースを開きました。

アプリケーション画面も開き、オブジェクトストアStore_nameがあって、プライマリキー(主キー)の登録が’member’であることを確認します。

アプリケーション画面にある’Store_name’とプライマリキー(主キー)

ここまでは(その4)までのおさらいです。

さて、オブジェクトストアStore_nameにレコード格納を開始しますが、データベースにおける面倒の始まりでもあります。

(その3)で紹介したトランザクションを発動(生成)した上での運用になるので、処理の階層構造がごちゃっとしてきます。

運用の流れとしては、データベースDB_nameを開いた成功イベント発火を受けて、まずは操作場になるトランザクションを書き込み可能モードで発動(生成)します。そのトランザクション上でオブジェクストアに書き込みなどの操作をして、返ってきた成功イベント発火を受けて処理し、そしてトランザクションの完遂(oncomplete)イベント発火を受けて処理し、ようやくデータベースを開いた成功イベントの最後でデータベースを閉鎖する運びになります。

これは、的確に且つ合理的に処理が進めばの流れです。ほら、もう読みたくなくないでしょ?

ともかく、上の流れの枠組みにあたるのは次のコードになります。オブジェクトストアの操作とその成功イベントなどの部分は省いてます。

そして、データベースのアップグレードイベントは出てきませんよー。ここにある定数txは成功イベント発火を受けての「利用」枠内のお話です。混同しないように気を付けましょう。

const openRequest = indexedDB.open('DB_name');

openRequest.addEventListener('success', (event)=>{
	const db = event.target.result;
	console.log(`データベースを開きました。`);

	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');

	(ここにオブジェクトストアへの操作が記述される。)

	//db.close();
}, false);

openRequest.addEventListener('error', (event)=>{
	console.error(`データベースの開始が失敗しました。`);
}, false);

コードの説明です。

db.transaction()メソッドでトランザクションが発動(生成)します。第一パラメータはオブジェクトストア名で第二パラメータは’readonly’か’readwrite’のモード指定です。

今回は書き込む(格納)ので’readwrite’モードです。この第二パラメータは省略すると’readonly’になります。

その返り値は、定数txに代入します。

そのtxに対してaddEventListener()メソッドでイベントリスナーを仕込み、完遂(oncomplete)、失敗(onerror)、中断(abort)の各イベントが発火するようにして、それを受けて処理が入ります。

そしてさらに、トランザクションtxのobjectStore()メソッドを利用し、パラメータにオブジェクトストア名を指定してトランザクションの上でオブジェクトストアを取得します。それを定数objectStoreに代入します。

ふと思うのですが、すでにトランザクションを発動する際にオブジェクトストア名を指定しているのだから重複していると感じます。そのうちパラメータを省けるようになるかもしれませんね。(おっと、余計な話。)

そして、(ここにオブジェクトストアへの操作が記述される。)の処理がなされた後、データベースを閉じてます。

(ここで閑話です。)

今まで、データベースを開いたイベント発火を受けた処理枠の最終行に、データベースの閉鎖close()メソッドを入れきました。

特に今回、そのままでは手順としては変だと感じます。しかし、現在のところ、データベースの閉鎖イベント発火を受けることができません。よって、挿入箇所に確証がないのです。

あってもなくても問題なく動きますが、気分が悪いので、とりあえず今はコメントアウトしておきます。

(閑話休題)やっとこ、レコードの格納です。

格納するレコードを仮につぎのようなオブジェクト(連想配列)とします。少し複雑ですがいろいろと実験できるように、つぎの形態にしました。

{
	index:{
		en:1,
		sn:'SN0003'
	},
	date:Date.now(),
	title:'ZINC',
	author:'hustlemouse',
	tag:['red','blue','yellow'],
	note:'Zn',
	member:2
}

つぎのコードがオブジェクトストアへの格納操作の記述です。put()メソッドのパラメータに前述のオブジェクトを入れます。そして定数storeRequestに代入して、その成功イベント発火とエラーイベント発火を受けての処理を記述します。

const storeRequest = objectStore.put({index:{en:1, sn:'SN0003'}, date:0, 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);

つぎのコードは処理全体をまとめたものです。Webブラウザのコンソールにコピー&ペーストして実行します。

必ず、冒頭のIndexedDBにはまってます。(その3)のコードを実行した後で作業します。(突然に、こっちを実行した時のエラーも確認しておくと良いでしょう。その内にそれら例外解消を紹介します。)

const openRequest = indexedDB.open('DB_name');

openRequest.addEventListener('success', (event)=>{
	const db = event.target.result;
	console.log(`データベースを開きました。`);

	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);

	//db.close();
}, false);

openRequest.addEventListener('error', (event)=>{console.error(`データベースの開始が失敗しました。`);}, false);
コンソールでレコードを格納した実行画面

つぎのように出力がされます。

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

よく、イベント発火順を確認してください。

そのままアプリケーション画面を開いてもレコードは確認できないと思います。(Google Chromeでの動作です。)プライマリキー(主キー)が表示されている上左の更新マークのボタンをクリックすると、レコードが現れます。

アプリケーション画面に現れたレコード

ありましたか?

確認が済んだら、(その2)にあったデータベース削除のソースコードを利用して削除しておきましょう。ごそっり掃除してくれます。

今更ですみません。Google Chromeでは、アプリケーション画面でデータベースを選択すると「データベースを削除」ボタンが現れます。これをクリックしてもデータベースの削除ができます。こっちの方が手間いらずです。他のブラウザも似たようにできると思います。

データベースを選択すると現れる「データベースを削除」ボタン

今回はレコードが格納できたところまでとします。

put()メソッドによるレコード格納を紹介しましたが、もうひとつ同様な機能のadd()メソッドがあります。

つぎの投稿では双方を比較しながら、できたらdelete()メソッドを紹介できればと思いますが、欲張りすぎかな。そかさ。