본문 바로가기
Frontend/JavaScript

JavaScript : 웹 스토리지 (3) - IndexedDB의 keyRange / index / opencusor

by 코딩쥐 2024. 8. 18.

IndexedDB에서 데이터를 효율적으로 검색하고 조작하는데 KeyRange, Index, OpenCursor를 사용할 수 있다. 

 

KeyRange

인덱스나 객체 저장소에서 키의 범위를 제한하는 역할을 한다. 이를 통해 특정 키 값이나 범위에 해당하는 항목만 선택할 수 있다. IDBKeyRange를 통해서 사용한다.

함수 설명
lowerBound(value, lowerOpen) 조회하려는 최소값 지정, lowerOpen이 true일 경우 값을 포함하지않음
upperBound(value, upperOpen) 조회하려는 최대값 지정, upperOpen이 true일 경우 값을 포함하지않음
bound(lower, upper, lowerOpen,
upperOpen)
조회하려는 최대값과 최소값 지정
only(value) 특정 값에 해당 하는 항목을 조회
includes(value) value가 지정된 키레인지의 범위에 포함되는 지를 확인
            // 데이터 추가
            const transaction = db.transaction("customer", "readwrite");
            const store = transaction.objectStore("customer");

            // 예시 데이터 추가
            store.add({ name: "김아무개", age: 30 });
            store.add({ name: "이몽룡", age: 25 });
            store.add({ name: "신데렐라", age: 35 });

            // 특정 범위의 데이터 검색
            const range = IDBKeyRange.bound(1, 3, true, false); // ID가 1 초과 3 이하인 항목 선택


<<전체 코드>> 

더보기
<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>IndexedDB KeyRange Example</title>
</head>

<body>
    <script>
        const db_name = "reservationDB";
        const db_version = 1;

        const request = indexedDB.open(db_name, db_version);

        request.onupgradeneeded = (e) => {
            const db = e.target.result;
            if (!db.objectStoreNames.contains("customer")) {
                db.createObjectStore("customer", {
                    keyPath: "id",
                    autoIncrement: true
                });
            }
        };

        request.onsuccess = (e) => {
            const db = e.target.result;
            console.log("IndexedDB를 여는 것을 성공했습니다.");

            // 데이터 추가
            const transaction = db.transaction("customer", "readwrite");
            const store = transaction.objectStore("customer");

            // 예시 데이터 추가
            store.add({ name: "김아무개", age: 30 });
            store.add({ name: "이몽룡", age: 25 });
            store.add({ name: "신데렐라", age: 35 });

            // 특정 범위의 데이터 검색
            const range = IDBKeyRange.bound(1, 3, true, false); // ID가 1 초과 3 이하인 항목 선택

            const request = store.openCursor(range);

            request.onsuccess = (event) => {
                const cursor = event.target.result;
                if (cursor) {
                    console.log("이름:", cursor.value.name, "나이:", cursor.value.age);
                    cursor.continue(); // 다음 항목으로 이동
                } else {
                    console.log("모든 항목을 순회했습니다.");
                }
            };
        };

        request.onerror = () => {
            console.log("IndexedDB를 여는 것을 실패했습니다.");
        };
    </script>
</body>

</html>

 

IndexedDB에 저장되어있는 값

 

IndexedDB에서 bound를 통해 id가 1초과 3이하인 값만 불러옴

 

Index

객체 저장소의 속성에 기반하여 데이터에 대한 추가적인 검색 기능을 제공한다. 기본적으로 객체 저장소를 생성할 때 설정한 keyPath가 인덱스로 사용되지만, 특정 속성(예: 출판 연도, 제목 등)을 기준으로 검색하려면 추가적인 인덱스를 생성해야 한다. createIndex의 경우에는 versionChange 에서 호출되어야 하기 때문에 인덱스 생성은 upgradeneeded 이벤트 핸들러 내에서 이루어져야 한다.

  • 스토어명.createIndex("기준 속성", "인덱스 이름", {unique: false | true })
    unique의 값이 true일 경우 인덱스 값은 중복될 수 없다. 
        request.onupgradeneeded = (e) => {
            const db = e.target.result;
            if (!db.objectStoreNames.contains("books")) {
                const objectStore = db.createObjectStore("books", {
                    keyPath: "id",
                    autoIncrement: true
                });

                // year에 대한 인덱스 생성
                objectStore.createIndex("year", "year", { unique: false });
            }
        };

 

year이라는 index가 생성된 모습을 볼 수 있다. 

 

openCursor() 

객체 저장소(object store)나 인덱스(index)에서 데이터 항목을 순회한다. 커서를 사용하면 데이터베이스의 여러 항목을 효과적으로 조회하고, 각 항목에 대해 필요한 작업을 수행할 수 있다. 

속성 설명
source 커서가 오픈된 오브젝트 스토어나 인덱스 객체를 나타냄
direction 커서의 진행 방법
next : 조회한 조건에 대해 오름차순으로 정렬 ( 기본값 ) 
nextunique : 조회한 조건에 대해 오름차순으로 정렬하며, 키가 중복되는 경우 처음 자료만 조회 
prev : 조회한 조건에 대해 내림차순으로 정렬
prevunique : 조회한 조건에 대해 내림차순으로 정렬하며, 키가 중복되는 경우 처음 자료만 조회
key 커서에 사용된 속성의 값을 나타냄
primaryKey 조회된 자료의 keypath 속성값을 나타냄
value 현재 가리키는 객체를 반환

 

함수 설명
advance(count) 커서의 포인터를 count만큼 이동
continue() 커서의 현재 포인터에서 다음 위치로 이동, IDBRequest와 success이벤트 발생시킴 
delete() 커서 위치에 있는 객체를 삭제
update(value) 커서 위치에 있는 객체의 내용을 value 값으로 수정
            const query = index.openCursor(range); // year인덱스 store의 범위 지정

            query.onsuccess = (event) => {
                const cursor = event.target.result;
                if (cursor) {
                    console.log("제목:", cursor.value.title, "연도:", cursor.value.year);
                    cursor.continue(); // 다음 항목으로 이동
                } else {
                    console.log("모든 항목을 순회했습니다.");
                }
            };

 

"year" 인덱스에 KeyRange를 사용하여 1990 ~ 2002 년도 범위를 설정하고, openCursor를 통해 순회하여 해당 결과에 대해 콘솔로 출력하였다. 

 

<<전체 코드>> 

더보기
<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>IndexedDB KeyRange Example</title>
</head>

<body>
    <script>
        const db_name = "bookDB";
        const db_version = 1;

        const request = indexedDB.open(db_name, db_version);

        request.onupgradeneeded = (e) => {
            const db = e.target.result;
            if (!db.objectStoreNames.contains("books")) {
                const objectStore = db.createObjectStore("books", {
                    keyPath: "id",
                    autoIncrement: true
                });

                // year에 대한 인덱스 생성
                objectStore.createIndex("year", "year", { unique: false });
            }
        };

        request.onsuccess = (e) => {
            const db = e.target.result;
            console.log("IndexedDB를 여는 것을 성공했습니다.");

            // 데이터 추가
            const transaction = db.transaction("books", "readwrite");
            const store = transaction.objectStore("books");

            // 예시 데이터 추가
            store.add({ title: "신데렐라", year: 2002 });
            store.add({ title: "백설공주", year: 1994 });
            store.add({ title: "잠자는 숲속의 공주", year: 2023 });

            const range = IDBKeyRange.bound(1990, 2002); // 1990 ~ 2002 사이의 range 설정
            const index = store.index("year");  // store의 year 인덱스를 가져옴
            const query = index.openCursor(range); // year인덱스 store의 범위 지정

            query.onsuccess = (event) => {
                const cursor = event.target.result;
                if (cursor) {
                    console.log("제목:", cursor.value.title, "연도:", cursor.value.year);
                    cursor.continue(); // 다음 항목으로 이동
                } else {
                    console.log("모든 항목을 순회했습니다.");
                }
            };
        };

        request.onerror = () => {
            console.log("IndexedDB를 여는 것을 실패했습니다.");
        };
    </script>
</body>

</html>