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);
アプリケーション画面でレコードの格納が確認できます。
プライマリキー(主キー)は配列のセットで運用されますから、指定が同じである限りは、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'}});
実行します。
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を学習して初めて出会いました。新しいことばかりでジジイにはきついです。そかさ。