프로그래밍/Js

indexedDB 기초 사용법

소행성왕자 2024. 10. 7. 16:34

IndexedDB는 키-값 쌍으로 데이터를 저장하는 객체 지향 데이터베이스입니다.

주로 대용량의 구조화된 데이터를 클라이언트에 저장하기 위해 사용됩니다.

주요 특징

비동기 작동: IndexedDB는 비동기 API를 사용하여 UI 블로킹을 방지합니다

트랜잭션 지원: 데이터의 일관성을 보장하기 위해 트랜잭션을 지원합니다

인덱싱: 빠른 검색을 위해 객체의 속성을 사용하여 인덱스를 생성할 수 있습니다

대용량 데이터 처리: 상대적으로 큰 양의 데이터를 로컬에 저장할 수 있습니다

전체소스

const IndexedDB = class {
    dbName = 'iDB';
    objName = '';
    constructor(dbName) {
        if(dbName) this.selectDb(dbName);
    }
    selectDb(dbName) {
        this.dbName = dbName;
        const result = indexedDB.open(this.dbName);
        result.onsuccess = _=>{
            result.result.close();
        };
    }

    getDbInfo() {
        return new Promise((resolve, reject)=>{
            let result = indexedDB.open(this.dbName);

            result.onerror=event=>{
                reject(false);
            };
            result.onsuccess=event=>{
                this.name = result.result.name;
                this.version = result.result.version;

                let dbInfo = {name:result.result.name, version:result.result.version};
                result.result.close();
                resolve(dbInfo);
            };
        })
    }

    async checkObject(objName) {
        return new Promise((resolve, reject)=>{
            const dbRequest = indexedDB.open(this.dbName);
            dbRequest.onsuccess = event=>{
                const db = event.target.result;
                const isExists = db.objectStoreNames.contains(objName);
                db.close();
                resolve(isExists);
            };
            dbRequest.onupgradeneeded=event=>{
                const db = event.target.result;
                const isExists = db.objectStoreNames.contains(objName);
                db.close();
                resolve(isExists);
            };
        });
    }

    async createObject(objName, schema) {
        let check = await this.checkObject(objName);
        if(check) return false;
        let dbInfo = await this.getDbInfo();

        return new Promise((resolve, reject) => {
            const newDb = indexedDB.open(dbInfo.name, dbInfo.version + 1);
            newDb.onupgradeneeded = event => {
                const db = event.target.result;
                const objectStore = db.createObjectStore(objName, { keyPath: 'name' }); // autoIncrement 제거
                for(const item in schema) {
                    if(schema[item] === 'index') objectStore.createIndex(item, item, {unique: false});
                }
                let returnData = {name: db.name, version: db.version, object: objName};
                resolve(returnData);
            };
            newDb.onerror = event => reject(event.target.error);
        });
    }

    async selectObject(objName) {
        let check = await this.checkObject(objName);
        if(!check) return false;
        this.objName = objName;

    }

    async insert(data) {
        const transactionObj = await this.getTransactonObject(this.objName);
        transactionObj.add(data);
    }

    async insertOrUpdate(data) {
        const transactionObj = await this.getTransactonObject(this.objName, 'readwrite');
        return new Promise((resolve, reject) => {
            const request = transactionObj.put(data);
            request.onerror = event => reject(event.target.error);
            request.onsuccess = event => resolve(event.target.result);
        });
    }

    async updateSpecificField(name, fieldPath, newValue) {
    const transactionObj = await this.getTransactonObject(this.objName, 'readwrite');
    return new Promise((resolve, reject) => {
        const getRequest = transactionObj.get(name);
        getRequest.onerror = event => reject(event.target.error);
        getRequest.onsuccess = event => {
            const data = event.target.result;
            if (data) {
                // 필드 경로를 따라 값을 업데이트
                const pathParts = fieldPath.split('.');
                let current = data;
                for (let i = 0; i < pathParts.length - 1; i++) {
                    current = current[pathParts[i]];
                }
                current[pathParts[pathParts.length - 1]] = newValue;

                // 업데이트된 데이터를 다시 저장
                const putRequest = transactionObj.put(data);
                putRequest.onerror = event => reject(event.target.error);
                putRequest.onsuccess = event => resolve(event.target.result);
            } else {
                reject(new Error('Data not found'));
            }
        };
    });
}

    async selectByIndex(indexName, indexValue) {
        const transactionObj = await this.getTransactonObject(this.objName, 'readonly');
        return new Promise((resolve, reject) => {
            const index = transactionObj.index(indexName);
            const request = index.get(indexValue);
            request.onsuccess = event => {
                resolve(event.target.result ? [event.target.result] : []);
            };
            request.onerror = event => reject(event.target.error);
        });
    }
    
    async selectAll() {
        const transactionObj = await this.getTransactonObject(this.objName, 'readonly');
        return new Promise((resolve, reject) => {
            const cursorRequest = transactionObj.openCursor();
            let selectData = [];
            cursorRequest.onsuccess = event => {
                const cursor = event.target.result;
                if (cursor) {
                    selectData.push(cursor.value);
                    cursor.continue();
                } else {
                    // 모든 데이터를 수집한 후 resolve 호출
                    resolve(selectData);
                }
            };
            cursorRequest.onerror = event => {
                reject(event.target.error);
            };
        });
    }

    getTransactonObject(objNAme, type) {
        const dbName = this.dbName;
        return new Promise((resolve, reject)=>{
            const dbRequest = indexedDB.open(dbName);
            dbRequest.onsuccess = event=>{
                const db = event.target.result;
                type=(type)?type:'readwrite';
                const transaction = db.transaction([objName], type);
                const transactionObj = transaction.objectStore(objName);
                resolve(transactionObj);
            }
        })
    }
}

 

  1. IndexedDB 클래스:
    이 클래스는 IndexedDB를 쉽게 사용할 수 있도록 래핑한 클래스입니다.
    a. 생성자:
    • dbName 파라미터를 받아 초기화합니다.
    • dbName이 제공되면 selectDb 메서드를 호출합니다.
    b. selectDb 메서드:
    • 지정된 이름의 데이터베이스를 열고 즉시 닫습니다.
    • 이는 데이터베이스의 존재를 확인하는 용도입니다.
    c. getDbInfo 메서드:
    • 데이터베이스의 이름과 버전을 비동기적으로 가져옵니다.
    • Promise를 반환하며, 성공 시 데이터베이스 정보를, 실패 시 false를 반환합니다.
    d. checkObject 메서드:
    • 특정 객체 저장소의 존재 여부를 비동기적으로 확인합니다.
    • Promise를 반환하며, 객체 저장소의 존재 여부를 boolean으로 반환합니다.
    e. createObject 메서드:
    • 새로운 객체 저장소를 생성합니다.
    • 이미 존재하면 false를 반환합니다.
    • 'name'을 키 경로로 사용하는 객체 저장소를 생성합니다.
    • 스키마에 따라 인덱스를 생성합니다.
    f. selectObject 메서드:
    • 특정 객체 저장소를 선택합니다.
    • 객체 저장소가 존재하지 않으면 false를 반환합니다.
    g. insert 메서드:
    • 데이터를 객체 저장소에 추가합니다.
    h. insertOrUpdate 메서드:
    • 데이터를 추가하거나 업데이트합니다.
    • IndexedDB의 put 메서드를 사용하여 upsert 기능을 구현합니다.
    i. updateSpecificField 메서드:
    • 특정 필드의 값만 업데이트합니다.
    • 객체의 중첩된 구조를 처리할 수 있습니다.
    • 데이터가 존재하지 않으면 에러를 발생시킵니다.
    j. selectByIndex 메서드:
    • 특정 인덱스를 사용하여 데이터를 조회합니다.
    • 결과를 배열 형태로 반환합니다.
    k. getTransactonObject 메서드:
    • 트랜잭션 객체를 생성하고 반환합니다.
    • 읽기 전용 또는 읽기/쓰기 트랜잭션을 생성할 수 있습니다.
  2. indexDBProc 함수:
    이 함수는 IndexedDB 클래스를 사용하여 실제 데이터 처리를 수행합니다.
    a. 데이터베이스와 객체 저장소 이름을 정의합니다.
    b. IndexedDB 인스턴스를 생성합니다.
    c. 데이터베이스를 선택합니다.
    d. 스키마를 정의합니다 ('name'을 키로, 'data'를 일반 필드로 설정).
    e. 객체 저장소를 생성합니다 (이미 존재하면 생성하지 않음).
    f. 객체 저장소를 선택합니다.
    g. updateSpecificField 메서드를 사용하여 특정 필드('CMBS_spot_askmarkup.value')를 업데이트합니다.
    h. 업데이트 성공 시 로그를 출력하고, 실패 시 에러를 콘솔에 출력합니다.

이 코드의 주요 특징:

  1. Promise 기반: 모든 비동기 작업은 Promise를 사용하여 처리됩니다.
  2. 모듈화: IndexedDB 작업을 클래스로 캡슐화하여 재사용성을 높였습니다.
  3. 유연성: 다양한 IndexedDB 작업(생성, 조회, 업데이트 등)을 지원합니다.
  4. 에러 처리: 대부분의 메서드에서 에러 처리를 포함하고 있습니다.
  5. 중첩 객체 지원: updateSpecificField 메서드를 통해 중첩된 객체 구조의 특정 필드를 업데이트할 수 있습니다.

이 코드는 IndexedDB를 효과적으로 사용하기 위한 좋은 구조를 가지고 있으며, 특히 특정 필드만 업데이트하는 기능은 데이터 관리에 유용합니다.

메소드 설명

selectDb(dbName) {
        this.dbName = dbName;
        const result = indexedDB.open(this.dbName);
        result.onsuccess = _=>{
            result.result.close();
        };
    }
    
    
메서드 정의:
selectDb는 dbName이라는 파라미터를 받는 메서드입니다.

데이터베이스 이름 설정:
this.dbName = dbName;
이 라인은 클래스의 dbName 속성을 입력받은 dbName 값으로 설정합니다.

데이터베이스 열기 요청:
const result = indexedDB.open(this.dbName);
indexedDB.open() 메서드를 호출하여 데이터베이스를 열려고 시도합니다.
이 메서드는 즉시 IDBOpenDBRequest 객체를 반환합니다.
이 작업은 비동기적으로 수행됩니다.

성공 이벤트 처리:
javascript
result.onsuccess = _ => {
    result.result.close();
};

onsuccess 이벤트 핸들러를 설정합니다.
데이터베이스 열기가 성공하면 이 핸들러가 호출됩니다.
핸들러 내에서 result.result로 열린 데이터베이스 객체에 접근합니다.
그리고 즉시 close() 메서드를 호출하여 데이터베이스 연결을 닫습니다.

주요 특징:
데이터베이스를 열고 즉시 닫습니다. 이는 데이터베이스의 존재 여부를 확인하는 용도로 보입니다.
실제로 데이터베이스를 사용하지는 않습니다. 단지 열 수 있는지 확인만 합니다.
에러 처리가 없어, 데이터베이스를 열 수 없는 경우에 대한 대응이 없습니다.
비동기 작업의 결과를 기다리지 않고 메서드가 종료됩니다. 따라서 이 메서드 호출 직후에 데이터베이스 작업을 수행하려 하면 문제가 발생할 수 있습니다.

개선 가능한 부분:
에러 처리 추가 (onerror 이벤트 핸들러 설정)
Promise를 반환하여 비동기 작업 완료를 기다릴 수 있게 만들기
데이터베이스를 열고 닫는 목적이 명확하지 않으므로, 목적에 따라 로직 수정 필요
이 메서드는 데이터베이스의 존재 여부를 확인하는 용도로 사용되는 것으로 보이지만, 실제 사용 시에는 주의가 필요합니다.
getDbInfo() {
        return new Promise((resolve, reject)=>{
            let result = indexedDB.open(this.dbName);

            result.onerror=event=>{
                reject(false);
            };
            result.onsuccess=event=>{
                this.name = result.result.name;
                this.version = result.result.version;

                let dbInfo = {name:result.result.name, version:result.result.version};
                result.result.close();
                resolve(dbInfo);
            };
        })
    }
    
    
메서드 정의:
getDbInfo()는 파라미터를 받지 않는 메서드입니다.
Promise 반환:
이 메서드는 새로운 Promise 객체를 생성하여 반환합니다. 이는 비동기 작업을 처리하기 위한 것입니다.

데이터베이스 열기 요청:
let result = indexedDB.open(this.dbName);
indexedDB.open() 메서드를 호출하여 this.dbName이라는 이름의 데이터베이스를 열려고 시도합니다.
이 메서드는 즉시 IDBOpenDBRequest 객체를 반환합니다.

에러 처리:
javascript
result.onerror = event => {
    reject(false);
};

데이터베이스를 여는 데 실패하면 이 핸들러가 호출됩니다.
Promise를 false 값으로 거부(reject)합니다.

성공 처리:
javascript
result.onsuccess = event => {
    this.name = result.result.name;
    this.version = result.result.version;

    let dbInfo = {name: result.result.name, version: result.result.version};
    result.result.close();
    resolve(dbInfo);
};

데이터베이스를 성공적으로 열면 이 핸들러가 호출됩니다.
this.name과 this.version에 데이터베이스의 이름과 버전을 저장합니다.
dbInfo 객체를 생성하여 데이터베이스의 이름과 버전 정보를 담습니다.
데이터베이스 연결을 닫습니다 (result.result.close()).
Promise를 dbInfo 객체로 해결(resolve)합니다.

주요 특징:
비동기 처리: Promise를 사용하여 비동기 작업을 처리합니다.
데이터베이스 정보 획득: 데이터베이스의 이름과 버전 정보를 가져옵니다.
연결 관리: 정보를 가져온 후 데이터베이스 연결을 즉시 닫습니다.
에러 처리: 데이터베이스를 열 수 없는 경우에 대한 기본적인 에러 처리가 포함되어 있습니다.
async checkObject(objName) {
        return new Promise((resolve, reject)=>{
            const dbRequest = indexedDB.open(this.dbName);
            dbRequest.onsuccess = event=>{
                const db = event.target.result;
                const isExists = db.objectStoreNames.contains(objName);
                db.close();
                resolve(isExists);
            };
            dbRequest.onupgradeneeded=event=>{
                const db = event.target.result;
                const isExists = db.objectStoreNames.contains(objName);
                db.close();
                resolve(isExists);
            };
        });
    }
    
    
메서드 정의:
checkObject는 objName이라는 파라미터를 받는 비동기 메서드입니다.
async 키워드로 선언되어 있어, 이 메서드는 항상 Promise를 반환합니다.
Promise 생성:
메서드 내부에서 새로운 Promise를 생성하여 반환합니다.
데이터베이스 열기 요청:
const dbRequest = indexedDB.open(this.dbName);
indexedDB.open() 메서드를 호출하여 this.dbName이라는 이름의 데이터베이스를 열려고 시도합니다.

성공 처리 (onsuccess 이벤트 핸들러):
javascript
dbRequest.onsuccess = event => {
    const db = event.target.result;
    const isExists = db.objectStoreNames.contains(objName);
    db.close();
    resolve(isExists);
};

데이터베이스를 성공적으로 열면 이 핸들러가 호출됩니다.
event.target.result로 데이터베이스 객체에 접근합니다.
db.objectStoreNames.contains(objName)를 사용하여 지정된 객체 저장소의 존재 여부를 확인합니다.
데이터베이스 연결을 닫습니다.
Promise를 isExists 값(true 또는 false)으로 해결(resolve)합니다.

업그레이드 필요 처리 (onupgradeneeded 이벤트 핸들러):
javascript
dbRequest.onupgradeneeded = event => {
    const db = event.target.result;
    const isExists = db.objectStoreNames.contains(objName);
    db.close();
    resolve(isExists);
};

데이터베이스 버전 업그레이드가 필요한 경우 이 핸들러가 호출됩니다.
성공 핸들러와 동일한 로직을 수행합니다.

주요 특징:
비동기 처리: Promise를 사용하여 비동기 작업을 처리합니다.
객체 저장소 확인: 특정 이름의 객체 저장소가 존재하는지 확인합니다.
연결 관리: 확인 후 데이터베이스 연결을 즉시 닫습니다.
버전 업그레이드 고려: onupgradeneeded 이벤트를 처리하여 버전 업그레이드 상황에서도 동작합니다.
async createObject(objName, schema) {
        let check = await this.checkObject(objName);
        if(check) return false;
        let dbInfo = await this.getDbInfo();

        return new Promise((resolve, reject) => {
            const newDb = indexedDB.open(dbInfo.name, dbInfo.version + 1);
            newDb.onupgradeneeded = event => {
                const db = event.target.result;
                const objectStore = db.createObjectStore(objName, { keyPath: 'name' }); // autoIncrement 제거
                for(const item in schema) {
                    if(schema[item] === 'index') objectStore.createIndex(item, item, {unique: false});
                }
                let returnData = {name: db.name, version: db.version, object: objName};
                resolve(returnData);
            };
            newDb.onerror = event => reject(event.target.error);
        });
    }
    
메서드 정의:
createObject는 objName과 schema라는 두 개의 파라미터를 받는 비동기 메서드입니다.
async 키워드로 선언되어 있어, 이 메서드는 항상 Promise를 반환합니다.

객체 저장소 존재 여부 확인:
javascript
let check = await this.checkObject(objName);
if(check) return false;

checkObject 메서드를 호출하여 해당 이름의 객체 저장소가 이미 존재하는지 확인합니다.
이미 존재한다면 false를 반환하고 메서드를 종료합니다.

데이터베이스 정보 가져오기:
javascript
let dbInfo = await this.getDbInfo();

getDbInfo 메서드를 호출하여 현재 데이터베이스의 이름과 버전 정보를 가져옵니다.

새로운 Promise 생성:
객체 저장소 생성 과정을 비동기적으로 처리하기 위해 새로운 Promise를 생성합니다.

데이터베이스 버전 업그레이드:
javascript
const newDb = indexedDB.open(dbInfo.name, dbInfo.version + 1);

현재 버전에서 1을 증가시켜 데이터베이스를 엽니다. 이는 구조 변경을 위한 버전 업그레이드를 트리거합니다.

업그레이드 이벤트 처리 (onupgradeneeded):
javascript
newDb.onupgradeneeded = event => {
    const db = event.target.result;
    const objectStore = db.createObjectStore(objName, { keyPath: 'name' });
    for(const item in schema) {
        if(schema[item] === 'index') objectStore.createIndex(item, item, {unique: false});
    }
    let returnData = {name: db.name, version: db.version, object: objName};
    resolve(returnData);
};

새로운 객체 저장소를 생성합니다. keyPath를 'name'으로 설정합니다.
schema 객체를 순회하며, 'index'로 표시된 항목에 대해 인덱스를 생성합니다.
생성된 객체 저장소의 정보를 포함한 객체를 생성하여 Promise를 해결(resolve)합니다.

에러 처리:
javascript
newDb.onerror = event => reject(event.target.error);

데이터베이스 열기 또는 업그레이드 과정에서 오류가 발생하면 Promise를 거부(reject)합니다.

주요 특징:
중복 방지: 이미 존재하는 객체 저장소의 재생성을 방지합니다.
버전 관리: 데이터베이스 버전을 자동으로 증가시켜 구조 변경을 수행합니다.
유연한 스키마: 제공된 스키마에 따라 동적으로 인덱스를 생성합니다.
비동기 처리: Promise를 사용하여 비동기 작업을 관리합니다.
async selectObject(objName) {
        let check = await this.checkObject(objName);
        if(!check) return false;
        this.objName = objName;

    }
    
메서드 정의:
selectObject는 objName이라는 하나의 파라미터를 받는 비동기 메서드입니다.
async 키워드로 선언되어 있어, 이 메서드는 항상 Promise를 반환합니다.

객체 저장소 존재 확인:
javascript
let check = await this.checkObject(objName);

this.checkObject(objName)을 호출하여 지정된 이름의 객체 저장소가 존재하는지 확인합니다.
await를 사용하여 비동기 작업의 결과를 기다립니다.

존재 여부에 따른 처리:
javascript
if(!check) return false;

만약 check가 false라면 (즉, 객체 저장소가 존재하지 않는다면), 메서드는 즉시 false를 반환하고 종료됩니다.

객체 저장소 이름 설정:
javascript
this.objName = objName;

객체 저장소가 존재한다면, 클래스의 objName 속성을 입력받은 objName 값으로 설정합니다.

주요 특징:
비동기 처리: async/await를 사용하여 비동기 작업을 동기적으로 보이게 처리합니다.
존재 확인: 작업을 수행하기 전에 객체 저장소의 존재 여부를 먼저 확인합니다.
상태 관리: 클래스의 상태(this.objName)를 업데이트합니다.

이 메서드의 목적:
이 메서드는 특정 객체 저장소를 "선택"하는 역할을 합니다.
선택된 객체 저장소의 이름을 클래스 인스턴스에 저장하여, 이후 다른 메서드에서 이 객체 저장소에 대한 작업을 수행할 수 있게 합니다.

사용 예시:
javascript
async function selectCustomerStore() {
    const indexedDB = new IndexedDB('myDatabase');
    const selected = await indexedDB.selectObject('customers');
    if (selected) {
        console.log('Customers object store selected');
    } else {
        console.log('Customers object store does not exist');
    }
}
async insertOrUpdate(data) {
        const transactionObj = await this.getTransactonObject(this.objName, 'readwrite');
        return new Promise((resolve, reject) => {
            const request = transactionObj.put(data);
            request.onerror = event => reject(event.target.error);
            request.onsuccess = event => resolve(event.target.result);
        });
    }
    
    
메서드 정의:
insertOrUpdate는 data라는 하나의 파라미터를 받는 비동기 메서드입니다.
async 키워드로 선언되어 있어, 이 메서드는 항상 Promise를 반환합니다.

트랜잭션 객체 획득:
javascript
const transactionObj = await this.getTransactonObject(this.objName, 'readwrite');

getTransactonObject 메서드를 호출하여 읽기/쓰기 권한을 가진 트랜잭션 객체를 얻습니다.
this.objName은 이전에 selectObject 메서드에서 설정된 객체 저장소의 이름입니다.
'readwrite' 매개변수는 이 트랜잭션이 읽기와 쓰기 모두 가능하다는 것을 나타냅니다.

Promise 생성 및 반환:
새로운 Promise를 생성하여 비동기 작업을 처리합니다.

데이터 삽입 또는 업데이트:
javascript
const request = transactionObj.put(data);

put 메서드를 사용하여 데이터를 삽입하거나 업데이트합니다.
put은 주어진 키가 이미 존재하면 해당 레코드를 업데이트하고, 존재하지 않으면 새 레코드를 삽입합니다.

에러 처리:
javascript
request.onerror = event => reject(event.target.error);

작업 중 오류가 발생하면 Promise를 거부(reject)하고 오류 정보를 전달합니다.

성공 처리:
javascript
request.onsuccess = event => resolve(event.target.result);

작업이 성공적으로 완료되면 Promise를 이행(resolve)하고 결과를 반환합니다.
반환되는 결과는 일반적으로 삽입/업데이트된 레코드의 키입니다.

주요 특징:
Upsert 기능: 이 메서드는 "upsert" (update or insert) 작업을 수행합니다. 즉, 데이터가 존재하면 업데이트하고, 존재하지 않으면 새로 삽입합니다.
비동기 처리: Promise를 사용하여 비동기 작업을 관리합니다.
트랜잭션 사용: 데이터베이스 일관성을 유지하기 위해 트랜잭션 내에서 작업을 수행합니다.

사용 예시:
javascript
async function updateUserData(userId, newData) {
    const indexedDB = new IndexedDB('myDatabase');
    await indexedDB.selectObject('users');
    try {
        const result = await indexedDB.insertOrUpdate({ id: userId, ...newData });
        console.log('User data updated, key:', result);
    } catch (error) {
        console.error('Error updating user data:', error);
    }
}

이 메서드는 IndexedDB에서 데이터를 효율적으로 삽입하거나 업데이트하는 데 사용됩니다. 단일 메서드로 두 가지 작업(삽입과 업데이트)을 처리할 수 있어 코드를 간결하게 유지할 수 있습니다.
async updateSpecificField(name, fieldPath, newValue) {
    const transactionObj = await this.getTransactonObject(this.objName, 'readwrite');
    return new Promise((resolve, reject) => {
        const getRequest = transactionObj.get(name);
        getRequest.onerror = event => reject(event.target.error);
        getRequest.onsuccess = event => {
            const data = event.target.result;
            if (data) {
                // 필드 경로를 따라 값을 업데이트
                const pathParts = fieldPath.split('.');
                let current = data;
                for (let i = 0; i < pathParts.length - 1; i++) {
                    current = current[pathParts[i]];
                }
                current[pathParts[pathParts.length - 1]] = newValue;

                // 업데이트된 데이터를 다시 저장
                const putRequest = transactionObj.put(data);
                putRequest.onerror = event => reject(event.target.error);
                putRequest.onsuccess = event => resolve(event.target.result);
            } else {
                reject(new Error('Data not found'));
            }
        };
    });
    
  
메서드 정의:
이 메서드는 name, fieldPath, newValue 세 개의 파라미터를 받는 비동기 메서드입니다.
async 키워드로 선언되어 있어, 항상 Promise를 반환합니다.

트랜잭션 객체 획득:
javascript
const transactionObj = await this.getTransactonObject(this.objName, 'readwrite');

읽기/쓰기 권한을 가진 트랜잭션 객체를 얻습니다.

Promise 생성:
새로운 Promise를 생성하여 비동기 작업을 처리합니다.

데이터 조회:
javascript
const getRequest = transactionObj.get(name);

name을 키로 사용하여 데이터를 조회합니다.

조회 에러 처리:
javascript
getRequest.onerror = event => reject(event.target.error);

조회 중 오류 발생 시 Promise를 거부(reject)합니다.

조회 성공 처리:
javascript
getRequest.onsuccess = event => { ... }

데이터 조회 성공 시 실행되는 콜백 함수입니다.

데이터 존재 확인 및 업데이트:
javascript
const data = event.target.result;
if (data) {
    // 필드 경로를 따라 값을 업데이트
    const pathParts = fieldPath.split('.');
    let current = data;
    for (let i = 0; i < pathParts.length - 1; i++) {
        current = current[pathParts[i]];
    }
    current[pathParts[pathParts.length - 1]] = newValue;
    // ...
}

조회된 데이터가 존재하면, 지정된 필드 경로를 따라 값을 업데이트합니다.
fieldPath를 '.' 기준으로 분리하여 중첩된 객체 구조를 탐색합니다.

업데이트된 데이터 저장:
javascript
const putRequest = transactionObj.put(data);
putRequest.onerror = event => reject(event.target.error);
putRequest.onsuccess = event => resolve(event.target.result);

수정된 데이터를 다시 저장합니다.
저장 중 오류 발생 시 Promise를 거부합니다.
저장 성공 시 Promise를 이행(resolve)하고 결과를 반환합니다.

데이터 없음 처리:
javascript
} else {
    reject(new Error('Data not found'));
}

조회된 데이터가 없으면 오류를 발생시킵니다.

주요 특징:
특정 필드 업데이트: 객체의 특정 필드만을 업데이트할 수 있습니다.
중첩 객체 지원: 점(.)으로 구분된 경로를 사용하여 중첩된 객체의 필드도 업데이트할 수 있습니다.
트랜잭션 사용: 데이터 일관성을 유지하기 위해 트랜잭션 내에서 작업을 수행합니다.
에러 처리: 다양한 상황(데이터 없음, 조회 실패, 저장 실패 등)에 대한 에러 처리를 포함합니다.

사용 예시:
javascript
async function updateUserEmail(userId, newEmail) {
    const indexedDB = new IndexedDB('myDatabase');
    await indexedDB.selectObject('users');
    try {
        await indexedDB.updateSpecificField(userId, 'contact.email', newEmail);
        console.log('User email updated successfully');
    } catch (error) {
        console.error('Error updating user email:', error);
    }
}

이 메서드는 복잡한 객체 구조에서 특정 필드만을 효율적으로 업데이트할 때 유용합니다. 전체 객체를 수정하지 않고도 원하는 필드만 변경할 수 있어, 데이터 관리가 더욱 유연해집니다.

호스트 코드

const indexDBProc = async (prdcd, receiveData) => {
    const dbName = 'coForwardIndexedDB';
    const objectName = 'data365';
    const indexDB = new IndexedDB(dbName);

    indexDB.selectDb(dbName);
    const schema={
        name: 'key',
        data: false,
    };

    await indexDB.createObject(objectName, schema);

    await indexDB.selectObject(objectName);

    //await indexDB.insertOrUpdate({ name: prdcd, data: receiveData });
    //console.log('Data inserted or updated for:', prdcd);

    try {
        await indexDB.updateSpecificField(prdcd, 'data.markup.value', newValue);
        console.log(`Updated CMBS_spot_askmarkup.value for ${prdcd} to ${newValue}`);
    } catch (error) {
        console.error('Error updating field:', error);
    }
}

indexDBProc('USDKRW', { prd:'USDKRW', data:{}}
// 모든 데이터 가져오기
const getAllData = async () => {
    const dbName = 'coForwardIndexedDB';
    const objectName = 'data365';
    const indexDB = new IndexedDB(dbName);

    try {
        // 데이터베이스 선택
        await indexDB.selectDb(dbName);

        // 객체 저장소 선택
        await indexDB.selectObject(objectName);

        // 모든 데이터 가져오기
        const allData = await indexDB.selectAll();

        console.log('All data from IndexedDB:');
        allData.forEach(item => {
            console.log(`Name: ${item.name}, Data:`, item.data);
        });

        return allData;
    } catch (error) {
        console.error('Error fetching all data:', error);
    }
};

// 함수 호출
getAllData().then(data => {
    if (data) {
        console.log(`Total items: ${data.length}`);
    }
});