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

IndexedDBにはまってます。(その8)で、オブジェクトストアの生成オプションの検証による「仕切り直し?」を受けて投稿した(その9)の続きになります。

キージェネレータがオフの条件で、プライマリキー(主キー)をキーワードの配列で指定する場合を紹介します。

(その8)の検証にあった指定をそのまま使います。

const Store_option = {keyPath:['member.id', 'member.name'], autoIncrement:false};

確認まで、プライマリキー(主キー)の階層概念は次ようになります。

{
	member:{
		id:2,
		name:'hustle'
	}
}

つぎのコードをWebブラウザ(Google Chromeを利用)のコンソールにコピー&ペーストし、エンターキーで実行して、オブジェクトストアStore_nameを生成します。

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.id', 'member.name'], autoIncrement:false};
	try {
		//オブジェクトストア操作箇所
		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);
	} catch(exception) {
		console.error(`例外が発生しました。_>${exception.message}`);
	}
}, false);
openRequest.addEventListener('success', (event)=>{
	const db = event.target.result;
	console.log(`データベースを開始しました。`);
	//db.close();
	db.addEventListener('close', ()=>{console.log(`データベースが閉鎖されました。`);}, false);
}, false);
openRequest.addEventListener('error', (event)=>{console.error(`データベースの開始に失敗しました。`);}, false);

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

エラー発火や例外発生が表示されなければ、オブジェクトストアの生成は成功しているはずです。

どんどん、データレコード(以後レコード)の格納をしてみましょう。プライマリキー(主キー)へは「member:{id:2, name:’hustle’}」と連想配列で指定します。

const storeRequest = objectStore.add({index:{en:1, sn:'SN0003'}, date:Date.now(), title:'ZINC', author:'hustlemouse', tag:['red','blue','yellow'], note:'Zn', member:{id:2, name:'hustle'}});

つぎのコードを実行します。

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');
		try {
			//レコード操作箇所
			const storeRequest = objectStore.add({index:{en:1, sn:'SN0003'}, date:Date.now(), title:'ZINC', author:'hustlemouse', tag:['red','blue','yellow'], note:'Zn', member:{id:2, name:'hustle'}});
			storeRequest.addEventListener('success', (event)=>{console.log(`レコードの書き込みに成功しました。`);}, false);	
			storeRequest.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);

アプリケーション画面でレコードの格納が確認できます。

アプリケーション画面で確認(keyPathに配列指定)

プライマリキー(主キー)は配列のセットで運用されますから、指定が同じである限りは、addやputの動作は今まで同様です。

それでは本当にセット運用なのか確認してみます。member.nameだけ「mouse」にしてaddします。

const storeRequest = objectStore.add({index:{en:1, sn:'SN0003'}, date:Date.now(), title:'ZINC', author:'hustlemouse', tag:['red','blue','yellow'], note:'Zn', member:{id:2, name:'mouse'}});

実行します。

アプリケーション画面で確認(keyPathに配列指定)

idが同じでも、新たにレコードが格納できます。確かにセット運用のようです。

では、連想配列を不完全にした場合はどうでしょう。member.idを「3」としてみます。

const storeRequest = objectStore.add({index:{en:1, sn:'SN0003'}, date:Date.now(), title:'ZINC', author:'hustlemouse', tag:['red','blue','yellow'], note:'Zn', member:{id:3}});

実行します。

コードを実行したコンソール画面(不完全連想配列)

例外が発生します。疑ったわけではありませんが、本当にセットでないとダメなんですね。

では、getしてみましょう。get()メソッドのパラメータは配列になります。

「get({id:2, name:’hustle’})」では例外が発生してダメです。格納は連想配列で、参照は配列っていうのもなんですかね。

const storeRequest = objectStore.get([2, 'hustle']);

つぎのコードを実行します。ストアオブジェクトの利用モードは「readonly」です。

const openRequest = indexedDB.open('DB_name');
openRequest.addEventListener('success', (event)=>{
	const db = event.target.result;
	console.log(`データベースを開始しました。`);
	if(db.objectStoreNames.contains('Store_name')) {
		//オブジェクトストアの操作モードは'readonly'
		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');
		try {
			//レコード操作箇所
			const storeRequest = objectStore.get([2, 'hustle']);
			storeRequest.addEventListener('success', (event)=>{
				console.log(`レコードの読み込みに成功しました。`);
				//取得レコードを表示
				console.dir(event.target.result);
			}, false);	
			storeRequest.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);
コードを実行したコンソール画面(配列)

もしやもしや、パラメータを不完全な配列にしたら複数のレコードが取得できるような妄想に駆られるので、試してみました。

const storeRequest = objectStore.get(2);
コードを実行したコンソール画面(不完全配列)

おっと残念、レコードは無い(undefined)と返ってきます。世の中そんなに甘くありませんでした。

「get([2])」でも同じく、もちろん「get({id:2})」では例外が発生してダメです。

レコードを削除するdelete()メソッドも同様に動作します。(ストアオブジェクトの利用モードを「readwrite」にするのをお忘れなく。)

これでプライマリキー(主キー)によるデータベース利用の初歩が概ね済んだと…思います。

つぎは、ラングオブジェクト(Range)を紹介します。

データベースでは複数のレコードを対象にする機能があり、それを実行するためにラングオブジェクトを利用します。これにレコードの対象範囲をしっかり登録してからデータベースに渡して、複数のレコードを利用します。

インデックスキー(補キー)やカーソルの紹介をして話がややこしくなる前に、ラングオブジェクトに挑みましょう。(いえー!自分に鼓舞。)

ラングの概念については、IndexedDBを学習して初めて出会いました。新しいことばかりでジジイにはきついです。そかさ。