Panduan ini membahas dasar-dasar IndexedDB API.
Kami menggunakan library IndexedDB Promised milik Jake Archibald, yang sangat mirip dengan IndexedDB API, tetapi menggunakan promise, yang dapat Anda await
untuk sintaksis yang lebih ringkas. Tindakan ini menyederhanakan API sekaligus
mempertahankan strukturnya.
Apa yang dimaksud dengan IndexedDB?
IndexedDB adalah sistem penyimpanan NoSQL berskala besar yang memungkinkan penyimpanan apa saja di browser pengguna. Selain tindakan pencarian, get, dan put seperti biasa, IndexedDB juga mendukung transaksi, dan sangat cocok untuk menyimpan data terstruktur dalam jumlah besar.
Setiap database IndexedDB bersifat unik untuk sebuah origin (biasanya domain situs atau subdomain), artinya database tersebut tidak dapat mengakses atau diakses oleh asal lain. Batas penyimpanan datanya biasanya besar, jika ada, tetapi browser yang berbeda menangani batas dan penghapusan data secara berbeda. Lihat bagian Bacaan lebih lanjut untuk informasi selengkapnya.
Persyaratan IndexedDB
- Database
- Nilai IndexedDB tertinggi. {i>Database<i} ini berisi penyimpanan objek, yang akan berisi data yang ingin Anda pertahankan. Anda dapat membuat beberapa database dengan nama apa pun yang Anda pilih.
- Penyimpanan objek
- Bucket individual untuk menyimpan data, serupa dengan tabel dalam database relasional.
Biasanya, ada satu penyimpanan objek untuk setiap jenis (bukan jenis data
JavaScript) data yang Anda simpan. Tidak seperti dalam tabel database, jenis data
JavaScript di app store tidak harus konsisten. Misalnya, jika aplikasi
memiliki penyimpanan objek
people
yang berisi informasi tentang tiga orang, properti usia orang-orang tersebut dapat berupa53
,'twenty-five'
, danunknown
. - Indeks
- Jenis penyimpanan objek untuk mengatur data di penyimpanan objek lain (disebut penyimpanan objek referensi) berdasarkan properti individual data. Indeks digunakan untuk mengambil catatan di penyimpanan objek oleh properti ini. Misalnya, jika Anda menyimpan orang, Anda mungkin ingin mengambilnya nanti berdasarkan nama, usia, atau hewan favorit mereka.
- Operasi
- Interaksi dengan database.
- Transaksi
- Wrapper di sekitar operasi atau grup operasi yang memastikan integritas database. Jika salah satu tindakan dalam transaksi gagal, tidak ada yang diterapkan dan database kembali ke status sebelum transaksi dimulai. Semua operasi baca atau tulis di IndexedDB harus menjadi bagian dari transaksi. Hal ini memungkinkan operasi baca-modifikasi-tulis atomik tanpa risiko konflik dengan thread lain yang bertindak pada database secara bersamaan.
- Kursor
- Mekanisme untuk melakukan iterasi pada beberapa record dalam database.
Cara memeriksa dukungan IndexedDB
IndexedDB hampir didukung secara universal.
Namun, jika Anda menggunakan browser lama, sebaiknya jangan
mendeteksi fitur untuk berjaga-jaga. Cara termudah adalah memeriksa objek window
:
function indexedDBStuff () {
// Check for IndexedDB support:
if (!('indexedDB' in window)) {
// Can't use IndexedDB
console.log("This browser doesn't support IndexedDB");
return;
} else {
// Do IndexedDB stuff here:
// ...
}
}
// Run IndexedDB code:
indexedDBStuff();
Cara membuka database
Dengan IndexedDB, Anda dapat membuat beberapa {i>database<i} dengan nama pilihan Anda. Jika tidak ada database saat Anda mencoba membukanya, database tersebut akan dibuat secara otomatis.
Untuk membuka database, gunakan metode openDB()
dari library idb
:
import {openDB} from 'idb';
async function useDB () {
// Returns a promise, which makes `idb` usable with async-await.
const dbPromise = await openDB('example-database', version, events);
}
useDB();
Metode ini menampilkan promise yang di-resolve ke objek database. Saat menggunakan metode openDB()
, berikan nama, nomor versi, dan objek peristiwa untuk menyiapkan database.
Berikut adalah contoh metode openDB()
dalam konteks:
import {openDB} from 'idb';
async function useDB () {
// Opens the first version of the 'test-db1' database.
// If the database does not exist, it will be created.
const dbPromise = await openDB('test-db1', 1);
}
useDB();
Tempatkan centang untuk dukungan IndexedDB di bagian atas fungsi anonim. Tindakan ini
akan keluar dari fungsi jika browser tidak mendukung IndexedDB. Jika dapat dilanjutkan, fungsi tersebut akan memanggil metode openDB()
untuk membuka database bernama 'test-db1'
.
Dalam contoh ini, objek peristiwa opsional telah diabaikan agar semuanya tetap sederhana, tetapi Anda harus menentukannya untuk melakukan pekerjaan yang bermakna dengan IndexedDB.
Cara bekerja dengan penyimpanan objek
Database IndexedDB berisi satu atau beberapa penyimpanan objek, yang masing-masing memiliki kolom untuk kunci, dan kolom lain untuk data yang terkait dengan kunci tersebut.
Membuat penyimpanan objek
Database IndexedDB yang terstruktur dengan baik harus memiliki satu penyimpanan objek untuk setiap jenis data yang perlu dipertahankan. Misalnya, situs yang mempertahankan profil dan catatan pengguna mungkin memiliki penyimpanan objek people
yang berisi objek person
, dan penyimpanan objek notes
yang berisi objek note
.
Untuk memastikan integritas database, Anda hanya dapat membuat atau menghapus penyimpanan objek dalam
objek peristiwa dalam panggilan openDB()
. Objek peristiwa mengekspos metode upgrade()
yang memungkinkan Anda membuat penyimpanan objek. Panggil metode
createObjectStore()
di dalam metode upgrade()
untuk membuat penyimpanan objek:
import {openDB} from 'idb';
async function createStoreInDB () {
const dbPromise = await openDB('example-database', 1, {
upgrade (db) {
// Creates an object store:
db.createObjectStore('storeName', options);
}
});
}
createStoreInDB();
Metode ini mengambil nama penyimpanan objek dan objek konfigurasi opsional yang memungkinkan Anda menentukan berbagai properti untuk penyimpanan objek.
Berikut adalah contoh cara menggunakan createObjectStore()
:
import {openDB} from 'idb';
async function createStoreInDB () {
const dbPromise = await openDB('test-db1', 1, {
upgrade (db) {
console.log('Creating a new object store...');
// Checks if the object store exists:
if (!db.objectStoreNames.contains('people')) {
// If the object store does not exist, create it:
db.createObjectStore('people');
}
}
});
}
createStoreInDB();
Dalam contoh ini, objek peristiwa diteruskan ke metode openDB()
untuk membuat
penyimpanan objek, dan seperti sebelumnya, pekerjaan membuat penyimpanan objek dilakukan
dalam metode upgrade()
objek peristiwa. Namun, karena browser menampilkan
error jika Anda mencoba membuat penyimpanan objek yang sudah ada, sebaiknya
gabungkan metode createObjectStore()
dalam pernyataan if
yang memeriksa
apakah penyimpanan objek tersebut ada atau tidak. Di dalam blok if
, panggil
createObjectStore()
untuk membuat penyimpanan objek bernama 'firstOS'
.
Cara menentukan kunci utama
Saat menentukan penyimpanan objek, Anda dapat menentukan cara data diidentifikasi secara unik di penyimpanan menggunakan kunci utama. Anda dapat menentukan kunci utama dengan menentukan jalur kunci atau dengan menggunakan generator kunci.
Jalur kunci adalah properti yang selalu ada dan berisi nilai unik. Misalnya, dalam kasus penyimpanan objek people
, Anda dapat memilih alamat email sebagai jalur kunci:
import {openDB} from 'idb';
async function createStoreInDB () {
const dbPromise = await openDB('test-db2', 1, {
upgrade (db) {
if (!db.objectStoreNames.contains('people')) {
db.createObjectStore('people', { keyPath: 'email' });
}
}
});
}
createStoreInDB();
Contoh ini membuat penyimpanan objek yang disebut 'people'
dan menetapkan properti email
sebagai kunci utama dalam opsi keyPath
.
Anda juga dapat menggunakan generator kunci seperti autoIncrement
. Generator kunci
membuat nilai unik untuk setiap objek yang ditambahkan ke penyimpanan objek. Secara default, jika Anda tidak menentukan kunci, IndexedDB akan membuat kunci dan menyimpannya secara terpisah dari data.
Contoh berikut membuat penyimpanan objek yang disebut 'notes'
dan menetapkan
kunci utama yang akan ditetapkan secara otomatis sebagai angka yang bertambah otomatis:
import {openDB} from 'idb';
async function createStoreInDB () {
const dbPromise = await openDB('test-db2', 1, {
upgrade (db) {
if (!db.objectStoreNames.contains('notes')) {
db.createObjectStore('notes', { autoIncrement: true });
}
}
});
}
createStoreInDB();
Contoh berikut serupa dengan contoh sebelumnya, tetapi kali ini
nilai yang bertambah otomatis secara eksplisit ditetapkan ke properti bernama 'id'
.
import {openDB} from 'idb';
async function createStoreInDB () {
const dbPromise = await openDB('test-db2', 1, {
upgrade (db) {
if (!db.objectStoreNames.contains('logs')) {
db.createObjectStore('logs', { keyPath: 'id', autoIncrement: true });
}
}
});
}
createStoreInDB();
Memilih metode yang akan digunakan untuk menentukan kunci bergantung pada data Anda. Jika data Anda memiliki properti yang selalu unik, Anda dapat menjadikannya keyPath
untuk menerapkan keunikan ini. Jika tidak, gunakan nilai yang bertambah otomatis.
Kode berikut membuat tiga penyimpanan objek yang menunjukkan berbagai cara menentukan kunci utama di penyimpanan objek:
import {openDB} from 'idb';
async function createStoresInDB () {
const dbPromise = await openDB('test-db2', 1, {
upgrade (db) {
if (!db.objectStoreNames.contains('people')) {
db.createObjectStore('people', { keyPath: 'email' });
}
if (!db.objectStoreNames.contains('notes')) {
db.createObjectStore('notes', { autoIncrement: true });
}
if (!db.objectStoreNames.contains('logs')) {
db.createObjectStore('logs', { keyPath: 'id', autoIncrement: true });
}
}
});
}
createStoresInDB();
Cara menentukan indeks
Indeks adalah jenis penyimpanan objek yang digunakan untuk mengambil data dari penyimpanan objek referensi berdasarkan properti tertentu. Indeks berada di dalam penyimpanan objek referensi dan berisi data yang sama, tetapi menggunakan properti yang ditentukan sebagai jalur kuncinya, bukan kunci utama penyimpanan referensi. Indeks harus dibuat saat Anda membuat penyimpanan objek, dan dapat digunakan untuk menentukan batasan unik pada data Anda.
Untuk membuat indeks, panggil metode createIndex()
pada instance penyimpanan objek:
import {openDB} from 'idb';
async function createIndexInStore() {
const dbPromise = await openDB('storeName', 1, {
upgrade (db) {
const objectStore = db.createObjectStore('storeName');
objectStore.createIndex('indexName', 'property', options);
}
});
}
createIndexInStore();
Metode ini membuat dan menampilkan objek indeks. Metode createIndex()
pada instance penyimpanan objek menggunakan nama indeks baru sebagai argumen pertama, dan argumen kedua mengacu pada properti pada data yang ingin Anda indeks. Argumen terakhir memungkinkan Anda menentukan dua opsi yang menentukan cara
indeks beroperasi: unique
dan multiEntry
. Jika unique
disetel ke true
, indeks tidak mengizinkan nilai duplikat untuk kunci tunggal. Selanjutnya, multiEntry
menentukan perilaku createIndex()
saat properti yang diindeks adalah array. Jika ditetapkan ke true
, createIndex()
akan menambahkan entri dalam indeks untuk setiap elemen array. Jika tidak, kode ini akan menambahkan satu entri yang berisi array.
Berikut contohnya:
import {openDB} from 'idb';
async function createIndexesInStores () {
const dbPromise = await openDB('test-db3', 1, {
upgrade (db) {
if (!db.objectStoreNames.contains('people')) {
const peopleObjectStore = db.createObjectStore('people', { keyPath: 'email' });
peopleObjectStore.createIndex('gender', 'gender', { unique: false });
peopleObjectStore.createIndex('ssn', 'ssn', { unique: true });
}
if (!db.objectStoreNames.contains('notes')) {
const notesObjectStore = db.createObjectStore('notes', { autoIncrement: true });
notesObjectStore.createIndex('title', 'title', { unique: false });
}
if (!db.objectStoreNames.contains('logs')) {
const logsObjectStore = db.createObjectStore('logs', { keyPath: 'id', autoIncrement: true });
}
}
});
}
createIndexesInStores();
Dalam contoh ini, penyimpanan objek 'people'
dan 'notes'
memiliki indeks. Untuk membuat indeks, pertama-tama tetapkan hasil createObjectStore()
(objek penyimpanan objek) ke variabel sehingga Anda dapat memanggil createIndex()
pada variabel tersebut.
Cara bekerja dengan data
Bagian ini menjelaskan cara membuat, membaca, memperbarui, dan menghapus data. Semua operasi ini bersifat asinkron, menggunakan promise dengan IndexedDB API menggunakan permintaan. Hal ini menyederhanakan API. Daripada memproses peristiwa yang dipicu oleh
permintaan tersebut, Anda dapat memanggil .then()
pada objek database yang ditampilkan dari
metode openDB()
untuk memulai interaksi dengan database, atau await
membuatnya.
Semua operasi data di IndexedDB dilakukan di dalam transaksi. Setiap operasi memiliki bentuk berikut:
- Mendapatkan objek database.
- Buka transaksi di database.
- Buka penyimpanan objek saat transaksi.
- Melakukan operasi pada penyimpanan objek.
Transaksi dapat dianggap sebagai wrapper yang aman di sekitar operasi atau sekelompok operasi. Jika salah satu tindakan dalam transaksi gagal, semua tindakan akan di-roll back. Transaksi bersifat khusus untuk satu atau beberapa penyimpanan objek, yang Anda tentukan saat membuka transaksi. Fitur ini dapat bersifat hanya-baca atau baca dan tulis. Ini menandakan apakah operasi di dalam transaksi membaca data atau membuat perubahan pada database.
Membuat data
Untuk membuat data, panggil metode add()
pada instance database dan teruskan data yang ingin Anda tambahkan. Argumen pertama metode add()
adalah penyimpanan objek yang ingin Anda tambahi data, dan argumen kedua adalah objek yang berisi kolom dan data terkait yang ingin Anda tambahkan. Berikut adalah contoh paling sederhana, dengan satu baris data ditambahkan:
import {openDB} from 'idb';
async function addItemToStore () {
const db = await openDB('example-database', 1);
await db.add('storeName', {
field: 'data'
});
}
addItemToStore();
Setiap panggilan add()
terjadi dalam transaksi. Jadi, meskipun promise berhasil diselesaikan, bukan berarti operasi tersebut berhasil. Untuk memastikan operasi penambahan dilakukan, Anda harus memeriksa apakah seluruh transaksi telah selesai menggunakan metode transaction.done()
. Ini adalah
janji yang di-resolve saat transaksi selesai sendiri, dan menolak jika
transaksi mengalami error. Anda harus melakukan pemeriksaan ini untuk semua operasi "tulis", karena itu satu-satunya cara Anda untuk mengetahui bahwa perubahan pada database telah benar-benar terjadi.
Kode berikut menunjukkan penggunaan metode add()
di dalam transaksi:
import {openDB} from 'idb';
async function addItemsToStore () {
const db = await openDB('test-db4', 1, {
upgrade (db) {
if (!db.objectStoreNames.contains('foods')) {
db.createObjectStore('foods', { keyPath: 'name' });
}
}
});
// Create a transaction on the 'foods' store in read/write mode:
const tx = db.transaction('foods', 'readwrite');
// Add multiple items to the 'foods' store in a single transaction:
await Promise.all([
tx.store.add({
name: 'Sandwich',
price: 4.99,
description: 'A very tasty sandwich!',
created: new Date().getTime(),
}),
tx.store.add({
name: 'Eggs',
price: 2.99,
description: 'Some nice eggs you can cook up!',
created: new Date().getTime(),
}),
tx.done
]);
}
addItemsToStore();
Setelah membuka database (dan membuat penyimpanan objek jika diperlukan), Anda harus
membuka transaksi dengan memanggil metode transaction()
di dalamnya. Metode ini
mengambil argumen untuk toko tempat Anda ingin bertransaksi, serta modenya.
Dalam hal ini, kita ingin menulis ke app store sehingga contoh ini
menentukan 'readwrite'
.
Langkah selanjutnya adalah mulai menambahkan item ke toko sebagai bagian dari transaksi.
Pada contoh sebelumnya, kita menangani tiga operasi di penyimpanan 'foods'
yang masing-masing menampilkan promise:
- Menambahkan catatan untuk roti lapis yang lezat.
- Menambahkan data untuk beberapa telur.
- Menandatangani bahwa transaksi selesai (
tx.done
).
Karena semua tindakan ini berbasis promise, kita harus menunggu semuanya selesai. Meneruskan promise ini ke Promise.all
adalah cara yang bagus dan ergonomis untuk menyelesaikan hal ini. Promise.all
menerima array promise dan selesai jika semua promise yang diteruskan ke promise tersebut telah di-resolve.
Untuk dua kumpulan data yang ditambahkan, antarmuka store
instance transaksi
memanggil add()
dan meneruskan data ke kumpulan data tersebut. Anda dapat melakukan await
panggilan Promise.all
sehingga selesai saat transaksi selesai.
Membaca data
Untuk membaca data, panggil metode get()
pada instance database yang Anda ambil menggunakan metode openDB()
.
get()
mengambil nama penyimpanan dan nilai kunci utama objek yang ingin Anda
ambil. Berikut adalah contoh dasarnya:
import {openDB} from 'idb';
async function getItemFromStore () {
const db = await openDB('example-database', 1);
// Get a value from the object store by its primary key value:
const value = await db.get('storeName', 'unique-primary-key-value');
}
getItemFromStore();
Seperti halnya add()
, metode get()
menampilkan promise, sehingga Anda dapat melakukan await
pada promise, atau menggunakan callback .then()
promise.
Contoh berikut menggunakan metode get()
pada penyimpanan objek 'foods'
database 'test-db4'
untuk mendapatkan satu baris dengan kunci utama 'name'
:
import {openDB} from 'idb';
async function getItemFromStore () {
const db = await openDB('test-db4', 1);
const value = await db.get('foods', 'Sandwich');
console.dir(value);
}
getItemFromStore();
Pengambilan satu baris dari database cukup mudah: buka database, lalu tentukan penyimpanan objek dan nilai kunci utama dari baris yang datanya ingin Anda dapatkan. Karena metode get()
menampilkan promise, Anda dapat melakukan await
padanya.
Memperbarui data
Untuk memperbarui data, panggil metode put()
pada penyimpanan objek. Metode put()
mirip dengan metode add()
dan juga dapat digunakan sebagai pengganti add()
untuk membuat data. Berikut ini contoh dasar penggunaan put()
untuk memperbarui baris di penyimpanan objek menurut nilai kunci utamanya:
import {openDB} from 'idb';
async function updateItemInStore () {
const db = await openDB('example-database', 1);
// Update a value from in an object store with an inline key:
await db.put('storeName', { inlineKeyName: 'newValue' });
// Update a value from in an object store with an out-of-line key.
// In this case, the out-of-line key value is 1, which is the
// auto-incremented value.
await db.put('otherStoreName', { field: 'value' }, 1);
}
updateItemInStore();
Seperti metode lain, metode ini menampilkan promise. Anda juga dapat menggunakan put()
sebagai
bagian dari transaksi. Berikut adalah contoh menggunakan toko 'foods'
dari sebelumnya
yang memperbarui harga sandwich dan telur:
import {openDB} from 'idb';
async function updateItemsInStore () {
const db = await openDB('test-db4', 1);
// Create a transaction on the 'foods' store in read/write mode:
const tx = db.transaction('foods', 'readwrite');
// Update multiple items in the 'foods' store in a single transaction:
await Promise.all([
tx.store.put({
name: 'Sandwich',
price: 5.99,
description: 'A MORE tasty sandwich!',
updated: new Date().getTime() // This creates a new field
}),
tx.store.put({
name: 'Eggs',
price: 3.99,
description: 'Some even NICER eggs you can cook up!',
updated: new Date().getTime() // This creates a new field
}),
tx.done
]);
}
updateItemsInStore();
Cara item diperbarui bergantung pada cara Anda menyetel kunci. Jika Anda menetapkan keyPath
,
setiap baris dalam penyimpanan objek akan dikaitkan dengan kunci inline. Contoh
sebelumnya memperbarui baris berdasarkan kunci ini, dan saat Anda mengupdate baris dalam
situasi ini, Anda harus menentukan kunci tersebut untuk mengupdate item yang sesuai di
penyimpanan objek. Anda juga dapat membuat kunci out-of-line dengan menetapkan
autoIncrement
sebagai kunci utama.
Menghapus data
Untuk menghapus data, panggil metode delete()
pada penyimpanan objek:
import {openDB} from 'idb';
async function deleteItemFromStore () {
const db = await openDB('example-database', 1);
// Delete a value
await db.delete('storeName', 'primary-key-value');
}
deleteItemFromStore();
Seperti add()
dan put()
, Anda dapat menggunakan ini sebagai bagian dari transaksi:
import {openDB} from 'idb';
async function deleteItemsFromStore () {
const db = await openDB('test-db4', 1);
// Create a transaction on the 'foods' store in read/write mode:
const tx = db.transaction('foods', 'readwrite');
// Delete multiple items from the 'foods' store in a single transaction:
await Promise.all([
tx.store.delete('Sandwich'),
tx.store.delete('Eggs'),
tx.done
]);
}
deleteItemsFromStore();
Struktur interaksi database sama dengan operasi
lainnya. Jangan lupa untuk memeriksa apakah seluruh transaksi telah selesai dengan menyertakan metode tx.done
dalam array yang Anda teruskan ke Promise.all
.
Mendapatkan semua data
Sejauh ini Anda hanya mengambil objek dari toko satu per satu. Anda juga dapat
mengambil semua data, atau subset, dari penyimpanan atau indeks objek menggunakan
metode getAll()
atau kursor.
Metode getAll()
Cara paling sederhana untuk mengambil semua data penyimpanan objek adalah dengan memanggil getAll()
pada penyimpanan atau indeks objek, seperti ini:
import {openDB} from 'idb';
async function getAllItemsFromStore () {
const db = await openDB('test-db4', 1);
// Get all values from the designated object store:
const allValues = await db.getAll('storeName');
console.dir(allValues);
}
getAllItemsFromStore();
Metode ini menampilkan semua objek di penyimpanan objek, tanpa batasan apa pun. Ini adalah cara paling langsung untuk mendapatkan semua nilai dari penyimpanan objek, tetapi juga yang paling tidak fleksibel.
import {openDB} from 'idb';
async function getAllItemsFromStore () {
const db = await openDB('test-db4', 1);
// Get all values from the designated object store:
const allValues = await db.getAll('foods');
console.dir(allValues);
}
getAllItemsFromStore();
Contoh ini memanggil getAll()
pada penyimpanan objek 'foods'
. Tindakan ini akan menampilkan semua objek dari 'foods'
yang diurutkan berdasarkan kunci utama.
Cara menggunakan kursor
Kursor adalah cara yang lebih fleksibel untuk mengambil beberapa objek. Kursor memilih setiap objek dalam penyimpanan atau indeks objek satu per satu, sehingga Anda dapat melakukan sesuatu dengan data saat dipilih. Kursor, seperti operasi database lainnya, bekerja dalam transaksi.
Untuk membuat kursor, panggil openCursor()
pada penyimpanan objek sebagai bagian dari transaksi. Dengan menggunakan penyimpanan 'foods'
dari
contoh sebelumnya, berikut cara memajukan kursor melalui semua baris data di
penyimpanan objek:
import {openDB} from 'idb';
async function getAllItemsFromStoreWithCursor () {
const db = await openDB('test-db4', 1);
const tx = await db.transaction('foods', 'readonly');
// Open a cursor on the designated object store:
let cursor = await tx.store.openCursor();
// Iterate on the cursor, row by row:
while (cursor) {
// Show the data in the row at the current cursor position:
console.log(cursor.key, cursor.value);
// Advance the cursor to the next row:
cursor = await cursor.continue();
}
}
getAllItemsFromStoreWithCursor();
Dalam hal ini, transaksi dibuka dalam mode 'readonly'
, dan
metode openCursor
dipanggil. Di loop while
berikutnya, baris di posisi kursor saat ini dapat membuat properti key
dan value
dibaca, dan Anda dapat beroperasi pada nilai-nilai tersebut dengan cara apa pun yang paling sesuai untuk aplikasi Anda. Jika sudah siap, Anda dapat memanggil metode continue()
objek cursor
untuk menuju ke baris berikutnya, dan loop while
akan berakhir saat kursor mencapai akhir set data.
Menggunakan kursor dengan rentang dan indeks
Indeks memungkinkan Anda mengambil data di penyimpanan objek berdasarkan properti selain kunci utama. Anda dapat membuat indeks di properti mana pun, yang menjadi keyPath
untuk indeks, menentukan rentang di properti tersebut, dan mendapatkan data dalam
rentang menggunakan getAll()
atau kursor.
Tentukan rentang Anda menggunakan objek IDBKeyRange
dan salah satu metode berikut:
upperBound()
.lowerBound()
.bound()
(keduanya).only()
.includes()
.
Metode upperBound()
dan lowerBound()
menentukan batas atas dan bawah
rentang tersebut.
IDBKeyRange.lowerBound(indexKey);
Atau:
IDBKeyRange.upperBound(indexKey);
Masing-masing mengambil satu argumen: nilai keyPath
indeks untuk item yang ingin
Anda tentukan sebagai batas atas atau bawah.
Metode bound()
menentukan batas atas dan bawah:
IDBKeyRange.bound(lowerIndexKey, upperIndexKey);
Rentang untuk fungsi ini bersifat inklusif secara default, yang berarti rentang tersebut menyertakan data yang ditentukan sebagai batas rentang. Untuk mengecualikan nilai tersebut,
tentukan rentang sebagai eksklusif dengan meneruskan true
sebagai argumen kedua untuk
lowerBound()
atau upperBound()
, atau sebagai argumen ketiga dan keempat dari
bound()
, untuk batas bawah dan atas masing-masing.
Contoh berikutnya menggunakan indeks di properti 'price'
di penyimpanan objek 'foods'
. Kini penyimpanan juga memiliki formulir yang terlampir dengan dua input untuk
batas atas dan bawah rentang. Gunakan kode berikut untuk menemukan makanan dengan
harga di antara batas tersebut:
import {openDB} from 'idb';
async function searchItems (lower, upper) {
if (!lower === '' && upper === '') {
return;
}
let range;
if (lower !== '' && upper !== '') {
range = IDBKeyRange.bound(lower, upper);
} else if (lower === '') {
range = IDBKeyRange.upperBound(upper);
} else {
range = IDBKeyRange.lowerBound(lower);
}
const db = await openDB('test-db4', 1);
const tx = await db.transaction('foods', 'readonly');
const index = tx.store.index('price');
// Open a cursor on the designated object store:
let cursor = await index.openCursor(range);
if (!cursor) {
return;
}
// Iterate on the cursor, row by row:
while (cursor) {
// Show the data in the row at the current cursor position:
console.log(cursor.key, cursor.value);
// Advance the cursor to the next row:
cursor = await cursor.continue();
}
}
// Get items priced between one and four dollars:
searchItems(1.00, 4.00);
Kode contoh terlebih dahulu akan mendapatkan nilai untuk batas dan memeriksa apakah batas tersebut
ada atau tidak. Blok kode berikutnya menentukan metode yang akan digunakan untuk membatasi rentang
berdasarkan nilai tersebut. Dalam interaksi database, buka penyimpanan objek pada transaksi seperti biasa, lalu buka indeks 'price'
pada penyimpanan objek. Indeks
'price'
memungkinkan Anda menelusuri item berdasarkan harga.
Kode kemudian membuka kursor pada indeks dan meneruskan dalam rentang. Kursor akan menampilkan promise yang mewakili objek pertama dalam rentang, atau undefined
jika tidak ada data dalam rentang tersebut. Metode cursor.continue()
menampilkan
kursor yang mewakili objek berikutnya, dan terus berlanjut melalui loop hingga Anda
mencapai akhir rentang.
Pembuatan versi database
Saat memanggil metode openDB()
, Anda dapat menentukan nomor versi database dalam parameter kedua. Dalam semua contoh dalam panduan ini, versi telah ditetapkan ke 1
, tetapi database dapat diupgrade ke versi baru jika Anda perlu mengubahnya dengan cara tertentu. Jika versi yang ditentukan lebih tinggi daripada versi database yang ada, callback upgrade
dalam objek peristiwa akan dieksekusi sehingga Anda dapat menambahkan penyimpanan dan indeks objek baru ke database.
Objek db
di callback upgrade
memiliki properti oldVersion
khusus,
yang menunjukkan nomor versi database yang dapat diakses browser.
Anda dapat meneruskan nomor versi ini ke dalam pernyataan switch
untuk mengeksekusi blok kode di dalam callback upgrade
berdasarkan nomor versi database yang ada. Berikut contohnya:
import {openDB} from 'idb';
const db = await openDB('example-database', 2, {
upgrade (db, oldVersion) {
switch (oldVersion) {
case 0:
// Create first object store:
db.createObjectStore('store', { keyPath: 'name' });
case 1:
// Get the original object store, and create an index on it:
const tx = await db.transaction('store', 'readwrite');
tx.store.createIndex('name', 'name');
}
}
});
Contoh ini menetapkan versi database terbaru ke 2
. Saat kode ini
pertama kali dieksekusi, database belum ada di browser, sehingga oldVersion
adalah 0
, dan pernyataan switch
dimulai pada case 0
. Dalam contoh ini, tindakan ini
akan menambahkan penyimpanan objek 'store'
ke database.
Poin utama: Dalam pernyataan switch
, biasanya ada break
setelah setiap blok
case
, tetapi ini sengaja tidak digunakan di sini. Dengan demikian, jika database yang ada tertinggal beberapa versi, atau jika database tersebut tidak ada, kode akan terus berlanjut melalui blok case
lainnya hingga diupdate. Jadi, dalam contoh ini,
browser terus mengeksekusi melalui case 1
, membuat indeks name
di
penyimpanan objek store
.
Untuk membuat indeks 'description'
pada penyimpanan objek 'store'
, update
nomor versi dan tambahkan blok case
baru seperti berikut:
import {openDB} from 'idb';
const db = await openDB('example-database', 3, {
upgrade (db, oldVersion) {
switch (oldVersion) {
case 0:
// Create first object store:
db.createObjectStore('store', { keyPath: 'name' });
case 1:
// Get the original object store, and create an index on it:
const tx = await db.transaction('store', 'readwrite');
tx.store.createIndex('name', 'name');
case 2:
const tx = await db.transaction('store', 'readwrite');
tx.store.createIndex('description', 'description');
}
}
});
Jika database yang Anda buat di contoh sebelumnya masih ada di browser, saat database ini dieksekusi, oldVersion
adalah 2
. Browser akan melewati case 0
dan case 1
, lalu mengeksekusi kode dalam case 2
, yang membuat indeks description
. Setelah itu, browser memiliki database di versi 3 yang berisi penyimpanan objek store
dengan indeks name
dan description
.
Bacaan lebih lanjut
Sumber daya berikut menyediakan informasi dan konteks selengkapnya untuk menggunakan IndexedDB.
Dokumentasi IndexedDB
idb
Repositori GitHub- Menggunakan IndexedDB
- Konsep Dasar di Balik IndexedDB
- Spesifikasi Indexed Database API 3.0