Questa guida illustra le nozioni di base
API IndexedDB.
Utilizziamo il libro di Jake Archibald
Promesso di Database indicizzato
, che è molto simile all'API IndexedDB, ma utilizza le promesse, che
puoi usare await
per una sintassi più concisa. Ciò semplifica l'API
mantenendone la struttura.
Che cos'è IndexedDB?
IndexedDB è un sistema di archiviazione NoSQL su larga scala che consente l'archiviazione di su qualsiasi elemento nel browser dell'utente. Oltre alle solite operazioni di ricerca, get e mettere azioni, IndexedDB supporta anche le transazioni ed è adatto per per archiviare grandi quantità di dati strutturati.
Ogni database IndexedDB è univoco per un'origine (in genere il dominio o il sottodominio del sito), nel senso che non è accessibile o accessibile da qualsiasi altra origine. I limiti di archiviazione dei dati di solito sono grandi, se presenti, ma browser diversi gestiscono i limiti e l'eliminazione dei dati in modo diverso. Consulta la sezione Per approfondire ulteriori informazioni.
Termini di IndexedDB
- Database
- Il livello più alto di IndexedDB. Contiene gli archivi di oggetti, che a loro volta contengono i dati che vuoi mantenere. Puoi creare più database con con il nome che preferisci.
- Archivio di oggetti
- Un singolo bucket per l'archiviazione dei dati, simile alle tabelle nei database relazionali.
In genere, esiste un archivio di oggetti per ogni tipo (non i dati JavaScript)
dei dati che stai archiviando. A differenza delle tabelle di database, i dati JavaScript
tipi di dati in un negozio non è necessario che siano coerenti. Ad esempio, se un'app
ha un archivio di oggetti
people
contenente informazioni su tre persone, ovvero Le proprietà per l'età delle persone potrebbero essere53
,'twenty-five'
eunknown
. - Indice
- Un tipo di archivio di oggetti per organizzare i dati in un altro archivio di oggetti (denominato archiviazione di oggetti di riferimento) in base a una singola proprietà dei dati. L'indice viene utilizzato per recuperare i record nell'archivio oggetti da questa proprietà. Ad esempio, se stai memorizzano le persone, potresti recuperarle in un secondo momento in base a nome, età l'animale preferito.
- Operazione
- Un'interazione con il database.
- Transazione
- Un wrapper attorno a un'operazione o un gruppo di operazioni che garantisce che il database dei dati. Se una delle azioni in una transazione non va a buon fine, nessuna verrà applicata e il database torna allo stato in cui si trovava prima della transazione è iniziato. Tutte le operazioni di lettura o scrittura in IndexedDB devono essere parte di una transazione. Ciò consente operazioni atomiche di lettura, modifica e scrittura senza il rischio di conflitti con altri thread che operano sul database contemporaneamente.
- Cursore
- Un meccanismo per eseguire l'iterazione su più record di un database.
Come verificare il supporto di IndexedDB
IndexedDB è quasi universalmente supportato.
Tuttavia, se utilizzi browser meno recenti, non è una cattiva idea
il rilevamento delle funzionalità
in caso di necessità. Il modo più semplice è controllare 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();
Come aprire un database
Con IndexedDB, puoi creare più database con il nome che preferisci. Se
un database non esiste quando provi ad aprirlo, creato automaticamente.
Per aprire un database, usa il metodo openDB()
dalla libreria 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();
Questo metodo restituisce una promessa che si risolve in un oggetto di database. Quando utilizzi il
openDB()
, fornisci un nome, un numero di versione e un oggetto eventi da impostare
per configurare il database.
Ecco un esempio del metodo openDB()
nel contesto:
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();
Posiziona il controllo per il supporto IndexedDB nella parte superiore della funzione anonima. Questo
esce dalla funzione se il browser non supporta IndexedDB. Se la funzione può
continua, chiama il metodo openDB()
per aprire un database denominato 'test-db1'
.
In questo esempio, l'oggetto eventi facoltativo è stato tralasciato per mantenere gli elementi
ma devi specificarlo per svolgere operazioni significative con IndexedDB.
Come utilizzare gli archivi di oggetti
Un database IndexedDB contiene uno o più archivi di oggetti, ciascuno con un per una chiave e un'altra colonna per i dati associati a quella chiave.
Crea archivi di oggetti
Un database IndexedDB ben strutturato deve avere un archivio di oggetti per ogni tipo
di dati che devono essere persistenti. Ad esempio, un sito che rende persistenti gli utenti
i profili e le note potrebbero avere un archivio di oggetti people
contenente person
e un archivio di oggetti notes
contenente note
oggetti.
Per garantire l'integrità del database, puoi creare o rimuovere archivi di oggetti solo nella
in una chiamata openDB()
. L'oggetto eventi espone un elemento upgrade()
che consente di creare archivi di oggetti. Chiama il
createObjectStore()
all'interno del metodo upgrade()
per creare l'archivio di oggetti:
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();
Questo metodo prende il nome dell'archivio di oggetti e una configurazione facoltativa che consente di definire varie proprietà dell'archivio oggetti.
Di seguito è riportato un esempio di come utilizzare 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();
In questo esempio, un oggetto event viene passato al metodo openDB()
per creare
l'archivio di oggetti e, come prima, la creazione dell'archivio di oggetti termina
nel metodo upgrade()
dell'oggetto evento. Tuttavia, poiché il browser genera un
errore se provi a creare un archivio di oggetti già esistente,
aggregare il metodo createObjectStore()
in un'istruzione if
che verifica
se l'archivio di oggetti esiste. Dall'interno del blocco if
, chiama
createObjectStore()
per creare un archivio di oggetti denominato 'firstOS'
.
Come definire le chiavi primarie
Quando definisci gli archivi di oggetti, puoi definire in che modo i dati vengono identificati in modo univoco utilizzando una chiave primaria. Puoi definire una chiave primaria definendo una chiave o usando un generatore di chiavi.
Un percorso chiave è una proprietà che esiste sempre e contiene un valore univoco. Per
Ad esempio, nel caso di un archivio di oggetti people
, potresti scegliere l'indirizzo email
come percorso della chiave:
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();
In questo esempio viene creato un archivio di oggetti denominato 'people'
e viene assegnato il valore email
come chiave primaria nell'opzione keyPath
.
Puoi anche usare un generatore di chiavi come autoIncrement
. Il generatore di chiavi
crea un valore univoco per ogni oggetto aggiunto all'archivio oggetti. Per impostazione predefinita,
Se non specifichi una chiave, IndexedDB crea una chiave e la archivia separatamente.
a partire dai dati.
L'esempio seguente crea un archivio di oggetti denominato 'notes'
e imposta il valore
chiave primaria da assegnare automaticamente come numero con incremento automatico:
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();
L'esempio seguente è simile a quello precedente, ma questa volta
il valore a incremento automatico è assegnato esplicitamente a una proprietà denominata '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();
La scelta del metodo da utilizzare per definire la chiave dipende dai dati. Se le tue
dati hanno una proprietà sempre univoca, puoi impostare keyPath
per
per applicare questa univocità. In caso contrario, utilizza un valore a incremento automatico.
Il seguente codice crea tre archivi di oggetti che mostrano i vari modi di definizione delle chiavi primarie negli archivi di oggetti:
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();
Come definire gli indici
Gli indici sono un tipo di archivio di oggetti utilizzato per recuperare dati dal riferimento di archiviazione di oggetti in base a una proprietà specificata. Un indice risiede all'interno dell'oggetto di riferimento Archivia e contiene gli stessi dati, ma utilizza la proprietà specificata come della chiave anziché la chiave primaria dell'archivio di riferimento. Gli indici devono essere creati quando crei i tuoi archivi di oggetti e può essere utilizzato per definire un vincolo univoco i tuoi dati.
Per creare un indice, chiama createIndex()
su un'istanza dell'archivio di oggetti:
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();
Questo metodo crea e restituisce un oggetto indice. Il metodo createIndex()
attivato
l'istanza dell'archivio di oggetti assume il nome del nuovo indice come primo
e il secondo argomento si riferisce alla proprietà sui dati che vuoi
indice. L'argomento finale consente di definire due opzioni che determinano il modo in cui
nell'indice: unique
e multiEntry
. Se il criterio unique
viene impostato su true
, il valore
non consente valori duplicati per una singola chiave. Poi, multiEntry
determina il comportamento di createIndex()
quando la proprietà indicizzata è un array. Se
è impostato su true
, createIndex()
aggiunge una voce all'indice per ogni array
. In caso contrario, aggiunge una singola voce contenente l'array.
Ecco un esempio:
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();
In questo esempio, gli archivi di oggetti 'people'
e 'notes'
hanno indici. A
crea gli indici, assegna prima il risultato di createObjectStore()
(un oggetto
store) a una variabile in modo da poter chiamare createIndex()
.
Come utilizzare i dati
Questa sezione descrive come creare, leggere, aggiornare ed eliminare dati. Questi
le operazioni sono tutte asincrone utilizzando promesse in cui l'API IndexedDB utilizza
richieste. Ciò semplifica l'API. Anziché ascoltare gli eventi attivati
la richiesta, puoi chiamare .then()
sull'oggetto di database restituito
Metodo openDB()
per avviare le interazioni con il database o await
il suo
per la creazione di contenuti.
Tutte le operazioni sui dati in IndexedDB vengono eseguite all'interno di una transazione. Ciascuna ha il seguente formato:
- Ottieni oggetto di database.
- Apri la transazione sul database.
- Apri archivio oggetti al momento della transazione.
- Eseguire un'operazione sull'archivio di oggetti.
Una transazione può essere considerata come un wrapper sicuro per un'operazione o un gruppo delle operazioni quotidiane. Se una delle azioni all'interno di una transazione non va a buon fine, tutte le il rollback di tutte le azioni. Le transazioni sono specifiche di uno o più archivi di oggetti, che definisci quando apri la transazione. Possono essere di sola lettura o lettura e scrivere. Indica se le operazioni all'interno della transazione o apportare una modifica al database.
Crea i dati
Per creare i dati, chiama add()
sull'istanza di database e passare i dati che vuoi aggiungere. add()
il primo argomento del metodo è l'archivio di oggetti a cui vuoi aggiungere i dati e
il secondo argomento è un oggetto contenente i campi e i dati associati che vuoi
da aggiungere. Ecco l'esempio più semplice, in cui viene aggiunta una singola riga di dati:
import {openDB} from 'idb';
async function addItemToStore () {
const db = await openDB('example-database', 1);
await db.add('storeName', {
field: 'data'
});
}
addItemToStore();
Ogni chiamata a add()
avviene all'interno di una transazione, quindi anche se la promessa si risolve
non significa necessariamente che l'operazione sia andata a buon fine. Per assicurarti
è stata eseguita l'operazione di aggiunta, devi verificare se
transazione è stata completata utilizzando il metodo transaction.done()
. Si tratta di un
che si risolve quando la transazione viene completata da sola e rifiuta se
errori di transazione. Devi eseguire questo controllo per tutte le operazioni di "scrittura" operazioni,
perché è l'unico modo per sapere che le modifiche apportate al database sono state effettivamente
è successo.
Il seguente codice mostra l'utilizzo del metodo add()
in una transazione:
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();
Una volta aperto il database (e creato un archivio di oggetti, se necessario), dovrai
per aprire una transazione chiamando il metodo transaction()
. Questo metodo
richiede un argomento per il negozio su cui vuoi effettuare transazioni, nonché la modalità.
In questo caso, vorremmo scrivere al negozio, in modo che questo esempio
specifica 'readwrite'
.
Il passaggio successivo consiste nell'iniziare ad aggiungere articoli al negozio come parte della transazione.
Nell'esempio precedente, abbiamo a che fare con tre operazioni su 'foods'
che ciascuno restituisca una promessa:
- aggiungo un record per un panino gustoso.
- Aggiunta di un record per alcune uova.
- Segnalazione del completamento della transazione (
tx.done
).
Poiché tutte queste azioni sono basate su promesse, dobbiamo aspettare
per completarli. Il rispetto di queste promesse
Promise.all
è un buon modo ergonomico per ottenere questo risultato. Promise.all
accetta un array di
promesse e finisce una volta risolte tutte le promesse fatte al riguardo.
Per i due record da aggiungere, l'interfaccia store
dell'istanza di transazione
chiama add()
e gli passa i dati. Puoi await
la chiamata Promise.all
in modo che finisca al termine della transazione.
Lettura di dati
Per leggere i dati, chiama get()
sull'istanza di database recuperata utilizzando il metodo openDB()
.
get()
prende il nome del negozio e il valore della chiave primaria dell'oggetto che
da recuperare. Ecco un esempio di base:
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();
Come nel caso di add()
, il metodo get()
restituisce una promessa, quindi puoi await
rla se
che preferisci oppure usa il callback .then()
della promessa.
L'esempio seguente utilizza il metodo get()
nel database 'test-db4'
'foods'
archivio di oggetti per ottenere una singola riga in base alla chiave primaria '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();
Il recupero di una singola riga dal database è piuttosto semplice: l'apertura
del database e specifica l'archivio oggetti e il valore della chiave primaria della riga
da cui vuoi prendere i dati. Poiché il metodo get()
restituisce una promessa, puoi
await
.
Aggiorna dati
Per aggiornare i dati, chiama il put()
sull'archivio di oggetti. Il metodo put()
è simile al metodo add()
e può anche essere utilizzato al posto di add()
per creare dati. Ecco un esempio di base
dell'utilizzo di put()
per aggiornare una riga in un archivio di oggetti in base al valore della chiave primaria:
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();
Come altri metodi, questo metodo restituisce una promessa. Puoi usare anche put()
come
di una transazione. Ecco un esempio di utilizzo dello store 'foods'
di un elenco precedente
che aggiorna il prezzo del panino e delle uova:
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();
Il modo in cui gli elementi vengono aggiornati dipende da come hai impostato una chiave. Se imposti un valore keyPath
,
Ogni riga nell'archivio oggetti è associata a una chiave in linea. Il precedente
esempio aggiorna le righe in base a questa chiave e quando aggiorni le righe
in ogni caso, dovrai specificare la chiave per aggiornare l'elemento appropriato nel
un archivio di oggetti. Puoi anche creare una chiave fuori riga impostando una proprietà
autoIncrement
come chiave primaria.
Elimina i dati
Per eliminare i dati, chiama il delete()
sull'archivio di oggetti:
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();
Come nel caso di add()
e put()
, puoi utilizzare questa opzione nell'ambito di una transazione:
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();
La struttura dell'interazione con il database è la stessa dell'altra
operazioni. Ricordati di controllare che l'intera transazione sia stata completata entro il giorno
incluso il metodo tx.done
nell'array passato a Promise.all
.
Recupero di tutti i dati in corso...
Finora hai recuperato solo oggetti dal datastore uno alla volta. Puoi anche
recupera tutti i dati o un sottoinsieme da un archivio o un indice di oggetti utilizzando
il metodo getAll()
o i cursori.
Il metodo getAll()
Il modo più semplice per recuperare tutti i dati di un archivio di oggetti è chiamare getAll()
sull'archivio o sull'indice di oggetti, in questo modo:
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();
Questo metodo restituisce tutti gli oggetti presenti nell'archivio, senza vincoli di qualunque cosa. È il modo più diretto per ottenere tutti i valori da un archivio di oggetti, ma anche il meno flessibile.
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();
Questo esempio chiama getAll()
nell'archivio di oggetti 'foods'
. Vengono restituiti tutti i valori
gli oggetti di 'foods'
, ordinati in base alla chiave primaria.
Come usare i cursori
I cursori sono un modo più flessibile per recuperare più oggetti. Un cursore seleziona ogni oggetto in un archivio o indice di oggetti uno alla volta, permettendoti di fare con i dati quando selezionato. I cursori, come le altre operazioni di database, delle transazioni.
Per creare un cursore, richiama openCursor()
sull'archivio di oggetti nell'ambito di una transazione. Utilizzo dello store 'foods'
da
esempi precedenti, ecco come avanzare un cursore su tutte le righe di dati
di un archivio di oggetti:
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();
In questo caso, la transazione viene aperta in modalità 'readonly'
e le relative
Viene chiamato il metodo openCursor
. In un ciclo while
successivo, la riga in corrispondenza
alla posizione corrente del cursore possono essere lette le proprietà key
e value
, e
puoi operare su questi valori nel modo più adatto alle tue esigenze
dell'app. Quando è tutto pronto, puoi chiamare continue()
dell'oggetto cursor
per andare alla riga successiva e il loop while
termina quando il cursore
raggiunge la fine del set di dati.
Utilizzare cursori con intervalli e indici
Gli indici consentono di recuperare i dati in un archivio di oggetti in base a una proprietà diversa dalla
e la chiave primaria. Puoi creare un indice su qualsiasi proprietà, che diventa keyPath
per l'indice, specifica un intervallo su quella proprietà e recupera i dati all'interno
intervallo utilizzando getAll()
o un cursore.
Definisci l'intervallo utilizzando l'oggetto IDBKeyRange
. e uno dei seguenti
metodo:
upperBound()
.lowerBound()
.bound()
(entrambi).only()
.includes()
.
I metodi upperBound()
e lowerBound()
specificano i limiti superiore e inferiore
dell'intervallo.
IDBKeyRange.lowerBound(indexKey);
Oppure:
IDBKeyRange.upperBound(indexKey);
Ognuno di loro ha un argomento: il valore keyPath
dell'indice per l'elemento che vuoi
da specificare come limite superiore o inferiore.
Il metodo bound()
specifica un limite massimo e uno inferiore:
IDBKeyRange.bound(lowerIndexKey, upperIndexKey);
L'intervallo per queste funzioni è inclusivo per impostazione predefinita, il che significa che include
i dati specificati come limiti dell'intervallo. Per escludere questi valori,
specifica l'intervallo come esclusivo passando true
come secondo argomento per
lowerBound()
o upperBound()
oppure come terzo e quarto argomento di
bound()
, rispettivamente, per il limite inferiore e quello superiore.
L'esempio seguente utilizza un indice nella proprietà 'price'
nell'oggetto 'foods'
. Allo store è ora allegato anche un modulo con due input per
limiti superiore e inferiore dell'intervallo. Utilizza il seguente codice per trovare alimenti con
prezzi compresi tra questi limiti:
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);
Il codice di esempio ottiene prima i valori per i limiti e controlla se i limiti
esistono. Il blocco di codice successivo stabilisce quale metodo utilizzare per limitare l'intervallo
in base a questi valori. Nell'interazione con il database, apri l'archivio di oggetti nella
come al solito, quindi apri l'indice 'price'
nell'archivio oggetti. La
L'indice 'price'
ti consente di cercare gli articoli in base al prezzo.
Il codice apre un cursore sull'indice e lo passa nell'intervallo. Il cursore
restituisce una promessa che rappresenta il primo oggetto nell'intervallo oppure undefined
se
non sono presenti dati nell'intervallo. Il metodo cursor.continue()
restituisce un
cursore che rappresenta l'oggetto successivo e continua nel loop finché non
raggiungere la fine dell'intervallo.
Controllo delle versioni del database
Quando chiami il metodo openDB()
, puoi specificare il numero di versione del database
nel secondo parametro. In tutti gli esempi di questa guida, la versione è stata
impostato su 1
, ma puoi eseguire l'upgrade di un database a una nuova versione se devi
modificarlo in qualche modo. Se la versione specificata è superiore a quella di
il database esistente, viene eseguito il callback upgrade
nell'oggetto evento,
consentendoti di aggiungere nuovi archivi e indici di oggetti al database.
L'oggetto db
nel callback upgrade
ha una proprietà oldVersion
speciale,
che indica il numero di versione del database a cui il browser ha accesso.
Puoi passare questo numero di versione in un'istruzione switch
per eseguire blocchi di
all'interno del callback upgrade
in base alla versione del database esistente
numero. Ecco un esempio:
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');
}
}
});
Questo esempio imposta la versione più recente del database su 2
. Quando il codice
viene eseguita per la prima volta, il database non esiste ancora nel browser, quindi oldVersion
è 0
e l'istruzione switch
inizia da case 0
. Nell'esempio, questo
aggiunge al database un archivio di oggetti 'store'
.
Punto chiave: nelle istruzioni switch
, di solito c'è un break
dopo ogni case
blocco note, che però non viene usato deliberatamente in questo caso. In questo modo, se l'istanza
del database è indietro di alcune versioni oppure, se non esiste, il codice continua
attraverso il resto dei blocchi di case
finché non viene aggiornato. Quindi, nell'esempio,
il browser continua a essere eseguito tramite case 1
, creando un indice name
nella
Archivio di oggetti store
.
Per creare un indice 'description'
nell'archivio di oggetti 'store'
, aggiorna il valore
numero di versione e aggiungi un nuovo blocco case
come segue:
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');
}
}
});
Se il database creato nell'esempio precedente esiste ancora nel browser,
quando viene eseguita, oldVersion
è 2
. Il browser ignora case 0
e
case 1
ed esegue il codice in case 2
, creando un description
indice. Successivamente, il browser avrà un database nella versione 3 contenente un store
un archivio di oggetti con indici name
e description
.
Per approfondire
Le seguenti risorse forniscono ulteriori informazioni e contesto per l'utilizzo di IndexedDB.
Documentazione IndexedDB
idb
Repository GitHub- Utilizzare IndexedDB
- Concetti di base alla base di IndexedDB
- Specifica dell'API Indexed Database 3.0