Signatur
Beschreibung
IDBIndex steht für einen Index auf einem IDBObjectStore. Mit einem Index findest du Datensätze über eine andere Eigenschaft als den Primärschlüssel, zum Beispiel Kunden über ihre E-Mail-Adresse oder Bestellungen über ihr Datum. Die Einträge im Index sind nach dem Indexschlüssel sortiert. Deshalb eignen sich Indizes auch für Bereichsabfragen mit IDBKeyRange und für sortierte Durchläufe mit Cursorn.
Einen Index legst du nur im upgradeneeded-Handler an, und zwar mit objectStore.createIndex(name, keyPath, options). Für Abfragen holst du den Index innerhalb einer Transaktion mit objectStore.index(name). Die wichtigsten Methoden sind:
get(key)/getKey(key): liefert den ersten passenden Datensatz bzw. dessen Primärschlüssel.getAll(query, count)/getAllKeys(query, count): liefert alle passenden Datensätze bzw. Primärschlüssel.count(query): zählt die passenden Einträge.openCursor(range, direction)/openKeyCursor(range, direction): durchläuft die Treffer in Indexreihenfolge.
Zu den Eigenschaften gehören name (im Upgrade umbenennbar), keyPath, multiEntry, unique und objectStore. Alle Methoden arbeiten asynchron und geben ein IDBRequest zurück. Das Ergebnis steht nach dem Ereignis success in request.result.
Mit unique: true verhindert ein Index doppelte Werte: Jeder Schreibversuch mit einem schon vorhandenen Wert schlägt mit einem ConstraintError fehl. Mit multiEntry: true legt ein Array-Wert für jedes Element einen eigenen Indexeintrag an. So lassen sich zum Beispiel Tags gut durchsuchen.
Parameter
| Name | Typ | Default | Beschreibung |
|---|---|---|---|
| $name Pflicht | string | Name des Index. Wird bei createIndex() angegeben und über objectStore.index(name) abgerufen. |
|
| $keyPath Pflicht | string|string[] | Eigenschaftspfad (auch mit Punkten, z. B. "adresse.plz") oder ein Array von Pfaden für einen zusammengesetzten Index. |
|
| $options.unique | boolean | false | Erzwingt eindeutige Indexwerte über alle Datensätze. |
| $options.multiEntry | boolean | false | Bei Array-Werten wird für jedes Element ein eigener Indexeintrag angelegt. Funktioniert nicht zusammen mit einem Array-keyPath. |
Rückgabewert
objectStore.createIndex() und objectStore.index() zurück. Die Abfragemethoden des Index liefern jeweils ein IDBRequest.Beispiele
Index beim Datenbank-Upgrade anlegen
const request = indexedDB.open('shop', 1);
request.addEventListener('upgradeneeded', () => {
const db = request.result;
const store = db.createObjectStore('kunden', { keyPath: 'id', autoIncrement: true });
// Eindeutiger Index auf der E-Mail-Adresse
store.createIndex('nachEmail', 'email', { unique: true });
// Mehrfach-Index für Tag-Arrays
store.createIndex('nachTag', 'tags', { multiEntry: true });
// Zusammengesetzter Index
store.createIndex('nachOrtUndName', ['ort', 'name']);
});
request.addEventListener('success', () => {
console.log('DB bereit:', request.result.name);
});
Datensatz über den Index finden (Promise-Wrapper)
const promisify = (req) => new Promise((resolve, reject) => {
req.onsuccess = () => resolve(req.result);
req.onerror = () => reject(req.error);
});
const findeKunde = async (db, email) => {
const tx = db.transaction('kunden', 'readonly');
const index = tx.objectStore('kunden').index('nachEmail');
console.log(index.name, index.keyPath, index.unique);
return promisify(index.get(email));
};
// Nutzung (db aus indexedDB.open)
const kunde = await findeKunde(db, 'anna@example.com');
console.log(kunde?.name ?? 'nicht gefunden');
Bereichsabfrage und Zählen mit IDBKeyRange
const tx = db.transaction('kunden', 'readonly');
const index = tx.objectStore('kunden').index('nachTag');
// Alle Kunden mit Tag 'premium' (max. 50)
const alle = index.getAll('premium', 50);
alle.onsuccess = () => console.log('Premium:', alle.result.length);
// Anzahl Tags alphabetisch zwischen 'a' und 'm'
const anzahl = index.count(IDBKeyRange.bound('a', 'm', false, true));
anzahl.onsuccess = () => console.log('Treffer a–l:', anzahl.result);
Sortiert rückwärts mit Cursor durchlaufen
const tx = db.transaction('kunden', 'readonly');
const index = tx.objectStore('kunden').index('nachOrtUndName');
// Nur Einträge mit ort === 'Berlin', absteigend nach Name
const range = IDBKeyRange.bound(['Berlin', ''], ['Berlin', '\uffff']);
index.openCursor(range, 'prev').onsuccess = (event) => {
const cursor = event.target.result;
if (!cursor) return console.log('Fertig');
console.log(cursor.key, '→ id', cursor.primaryKey);
cursor.continue();
};
// Wichtig · Fallstricke
- Nur im Upgrade anlegen:
createIndex()unddeleteIndex()funktionieren nur in einerversionchange-Transaktion, also imupgradeneeded-Handler. Zu jeder anderen Zeit wird einInvalidStateErrorausgelöst. - Lebensdauer der Transaktion: Ein
IDBIndexgehört zu genau einer Transaktion. Sie wird automatisch abgeschlossen, sobald keine Anfragen mehr offen sind. Wartest du dazwischen mitawaitauf etwas anderes (z. B.fetch), sind spätere Aufrufe ungültig und werfen einenTransactionInactiveError. - Nicht indexierbare Werte: Datensätze ohne die Index-Eigenschaft oder mit einem ungültigen Schlüsseltyp (z. B.
boolean,null, Objekt) tauchen im Index nicht auf. Boolesche Flags lassen sich deshalb nicht direkt indexieren. Speichere sie stattdessen als0/1. get()liefert bei mehreren Treffern nur den ersten Datensatz in Schlüsselreihenfolge. Für alle Treffer nimmst dugetAll()oder einen Cursor.unique: truegilt schon beim Anlegen des Index: Gibt es bereits doppelte Werte, bricht das Upgrade mit einemConstraintErrorab.- Kompatibilität: Alle modernen Browser unterstützen die API.
getAll()undgetAllKeys()gibt es in Safari erst ab Version 10.1. Beim Umbenennen überindex.nameund bei zusammengesetzten Schlüsseln hatten ältere Edge- und IE-Versionen Lücken. Im privaten Modus mancher Browser ist IndexedDB eingeschränkt. - Sicherheit: Die Daten folgen der Same-Origin-Policy, sind aber nicht verschlüsselt. Sensible Daten solltest du nicht im Klartext speichern.