Start · Sprachen · JavaScript · Referenz · IDBIndex

IDBIndex

Schnittstelle

Das <code>IDBIndex</code>-Interface gibt asynchronen Zugriff auf einen Index eines Object Stores in IndexedDB. Damit lassen sich Datensätze über andere Eigenschaften als den Primärschlüssel abfragen.

seit JavaScript Baseline: alle modernen Browser (getAll/getAllKeys Kategorie: webapi

Signatur

interface IDBIndex

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

Typ
IDBIndex
Beschreibung
Geben 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);
});
DB bereit: shop

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');
nachEmail email true Anna

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);
Premium: 12 Treffer a–l: 37

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();
};
[ 'Berlin', 'Zoe' ] → id 7 [ 'Berlin', 'Anna' ] → id 1 Fertig

// Wichtig · Fallstricke

  • Nur im Upgrade anlegen: createIndex() und deleteIndex() funktionieren nur in einer versionchange-Transaktion, also im upgradeneeded-Handler. Zu jeder anderen Zeit wird ein InvalidStateError ausgelöst.
  • Lebensdauer der Transaktion: Ein IDBIndex gehört zu genau einer Transaktion. Sie wird automatisch abgeschlossen, sobald keine Anfragen mehr offen sind. Wartest du dazwischen mit await auf etwas anderes (z. B. fetch), sind spätere Aufrufe ungültig und werfen einen TransactionInactiveError.
  • 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 als 0/1.
  • get() liefert bei mehreren Treffern nur den ersten Datensatz in Schlüsselreihenfolge. Für alle Treffer nimmst du getAll() oder einen Cursor.
  • unique: true gilt schon beim Anlegen des Index: Gibt es bereits doppelte Werte, bricht das Upgrade mit einem ConstraintError ab.
  • Kompatibilität: Alle modernen Browser unterstützen die API. getAll() und getAllKeys() gibt es in Safari erst ab Version 10.1. Beim Umbenennen über index.name und 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.