上次介紹的idb的文章裡,少講到了一個部份:Cursor
這個功能通常會用在資料量非常巨大,或是要針對整個資料做運算時使用,可以節省大量運算資源消耗。
基本操作
cursor類似於資料庫的游標,依序一次抓一筆資料來進行處理,目前市面上成熟的資料庫都有這樣的功能。關於 Cursor
的詳細說明可以參考這裡
這邊我們關注如何利用idb來使用這個功能
範例:取得學生們(students)內的本次考試最高的得分score:
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| let max; database.then(async(db) => { const cursor = await db.transaction('students').store.openCursor(); max = cursor.value.score; while(cursor) { if(cursor.value.score > max) max = cursor.value.score; cursor = await cursor.continue(); } console.log('最高分', max); });
|
除了直接遍歷整個資料庫外,也能使用index來篩出最需要的數據,加快執行效率
範例:取得學生們(students)內就讀學校(school)是建國高中,本次考試最高的得分score:
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| let max; database.then(async(db) => { const range = IDBKeyRange.only('建國高中'); const cursor = await db.transaction('students').store.index('school').openCursor(range);
max = cursor.value.score; while(cursor) { if(cursor.value.score > max) max = cursor.value.score; cursor = await cursor.continue(); } console.log('最高分', max); });
|
排序
indexedDB有幾個特點:
- 使用index的話會自動根據index的值做從小到大來排序給資料
- cursor可以從資料尾部倒著讀
從這邊我們可以發現:使用index獲取資料是隱含排序功能的,且利用cursor倒著讀的特性,我們可以取得從大到小排序好的資料
範例:取得學生們(students),本次考試最高的得分(score)的前20名,並降冪排序:
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| database.then(async(db) => { let read = 20; let students = []; const cursor = await db.transaction('students').store.index('score').openCursor(null, "prev");
max = cursor.value.score; while(cursor && read !== 0) { read -= 1; students.push(cursor.value); cursor = await cursor.continue(); } console.log('分數前20名', students); });
|
補充
由於目前indexedDB並不支援多個index範圍查詢,所以如過還要多設定過濾條件的話,得直接在while裡面設置。
比如說以前一個範例來講,我只要找出建中最高分前20位,可寫成
1 2 3 4 5
| while(cursor && read !== 0) { read -= 1; if(cursor.value.school === '建國高中') students.push(cursor.value); cursor = await cursor.continue(); }
|
逐筆修正
如果這次大家分數實在太差,為了不要讓太多人被當掉,長官決定讓所有人成績開根號x10,有沒有比較便捷的作法呢?
1 2 3 4 5 6 7 8 9 10 11
| database.then(async(db) => { const cursor = await db.transaction('students').store.openCursor();
while(cursor) { const student = cursor.value; student.score = Math.sqrt(student.score) * 10; await cursor.update(student); cursor = await cursor.continue(); } });
|