Start · Sprachen · JavaScript · Referenz · IDBCursorWithValue

IDBCursorWithValue

Schnittstelle

Ein IndexedDB-Cursor, der beim Durchlaufen von Object Stores oder Indizes neben Schlüssel und Primärschlüssel auch den <code>value</code> des aktuellen Datensatzes liefert.

seit JavaScript Baseline: alle modernen Browser (IndexedDB 2.0) Kategorie: webapi

Signatur

interface IDBCursorWithValue extends IDBCursor

Beschreibung

IDBCursorWithValue erweitert IDBCursor um die schreibgeschützte Eigenschaft value. Darüber lesen Sie den vollständigen Datensatz an der aktuellen Cursor-Position aus. Solche Cursor bekommen Sie von IDBObjectStore.openCursor() und IDBIndex.openCursor(). Die Methoden openKeyCursor() liefern dagegen ein einfaches IDBCursor-Objekt ohne Wert.

Mit dem Cursor gehen Sie Datensatz für Datensatz durch einen Store oder Index, optional eingegrenzt durch einen IDBKeyRange und eine Richtung ("next", "prev", "nextunique", "prevunique"). Das ist sinnvoll, wenn Sie Daten filtern, seitenweise laden oder während des Durchlaufs ändern wollen, statt mit getAll() alles auf einmal in den Speicher zu holen.

Von IDBCursor geerbt sind die Eigenschaften source, direction, key, primaryKey und request sowie die Methoden advance(count), continue(key?), continuePrimaryKey(key, primaryKey), update(value) und delete(). Jeder Schritt des Cursors löst erneut das success-Ereignis am selben IDBRequest aus. Am Ende ist request.result gleich null.

Parameter

Name Typ Default Beschreibung
$value any Eigenschaft (nur lesbar): der per structured clone kopierte Wert des aktuellen Datensatzes. Wenn Sie das Objekt ändern, ändert sich die Datenbank nicht; dafür brauchen Sie cursor.update().
$update(value) (value: any) => IDBRequest Geerbte Methode: überschreibt den aktuellen Datensatz. Funktioniert nur in einer readwrite-Transaktion.
$delete() () => IDBRequest Geerbte Methode: löscht den aktuellen Datensatz. Funktioniert nur in einer readwrite-Transaktion.
$continue(key) (key?: any) => void Geerbte Methode: springt zum nächsten Datensatz oder zum ersten Datensatz mit dem Schlüssel key oder einem Schlüssel dahinter.
$advance(count) (count: number) => void Geerbte Methode: überspringt count Datensätze. Nützlich für Seitenumbrüche (Paginierung).

Rückgabewert

Typ
IDBCursorWithValue | null
Beschreibung
Steht im success-Ereignis in request.result. Der Wert ist null, wenn es keine weiteren Datensätze mehr gibt.

Beispiele

Alle Datensätze eines Object Stores durchlaufen

const openReq = indexedDB.open('shop', 1);

openReq.onupgradeneeded = () => {
  const db = openReq.result;
  const store = db.createObjectStore('produkte', { keyPath: 'id' });
  store.put({ id: 1, name: 'Tastatur', preis: 49 });
  store.put({ id: 2, name: 'Maus', preis: 19 });
};

openReq.onsuccess = () => {
  const db = openReq.result;
  const store = db.transaction('produkte').objectStore('produkte');
  const cursorReq = store.openCursor();

  cursorReq.onsuccess = () => {
    const cursor = cursorReq.result; // IDBCursorWithValue oder null
    if (!cursor) {
      console.log('Fertig');
      return;
    }
    console.log(cursor.key, cursor.value.name);
    cursor.continue();
  };
};
1 Tastatur 2 Maus Fertig

Preise während des Durchlaufs aktualisieren (update)

const erhoehePreise = (db, prozent) => new Promise((resolve, reject) => {
  const tx = db.transaction('produkte', 'readwrite');
  const req = tx.objectStore('produkte').openCursor();

  req.onsuccess = () => {
    const cursor = req.result;
    if (!cursor) return;
    const produkt = { ...cursor.value };
    produkt.preis = Math.round(produkt.preis * (1 + prozent / 100));
    cursor.update(produkt); // schreibt den geänderten Datensatz zurück
    cursor.continue();
  };
  tx.oncomplete = () => resolve();
  tx.onerror = () => reject(tx.error);
});

// Aufruf: await erhoehePreise(db, 10);

Über einen Index mit Schlüsselbereich rückwärts iterieren

// Voraussetzung: store.createIndex('nachPreis', 'preis') im upgradeneeded
const teuersteUnter = (db, maxPreis) => new Promise((resolve) => {
  const ergebnis = [];
  const index = db.transaction('produkte').objectStore('produkte').index('nachPreis');
  const range = IDBKeyRange.upperBound(maxPreis);
  const req = index.openCursor(range, 'prev');

  req.onsuccess = () => {
    const cursor = req.result;
    if (!cursor || ergebnis.length === 3) return resolve(ergebnis);
    ergebnis.push(`${cursor.value.name}: ${cursor.value.preis} €`);
    cursor.continue();
  };
});

console.log(await teuersteUnter(db, 50));
["Tastatur: 49 €", "Maus: 19 €"]

Veraltete Einträge per delete() entfernen

const tx = db.transaction('logs', 'readwrite');
const grenze = Date.now() - 7 * 24 * 60 * 60 * 1000;
const req = tx.objectStore('logs').openCursor();

req.onsuccess = () => {
  const cursor = req.result;
  if (!cursor) return;
  if (cursor.value.zeitstempel < grenze) {
    cursor.delete();
  }
  cursor.continue();
};

tx.oncomplete = () => console.log('Aufräumen abgeschlossen');
Aufräumen abgeschlossen

// Wichtig · Fallstricke

  • Transaktion läuft ab: Rufen Sie continue() oder advance() synchron im success-Handler auf. Wenn Sie dazwischen etwa mit await fetch() warten, schließt sich die Transaktion automatisch, und der nächste Aufruf wirft TransactionInactiveError.
  • Nur ein Schritt pro Ereignis: Wird continue() zweimal im selben Durchlauf aufgerufen, kommt es zu einem InvalidStateError.
  • update() und delete() funktionieren nur in readwrite-Transaktionen, sonst wirft der Browser ReadOnlyError. Bei Stores mit keyPath darf update() den Primärschlüssel nicht ändern, sonst folgt ein DataError.
  • value ist eine Kopie. Direkte Änderungen daran werden nur mit update() gespeichert.
  • Für reine Schlüssellisten ist openKeyCursor() sparsamer, weil der Browser keine Werte deserialisieren muss. Für kleine Datenmengen sind getAll() und getAllKeys() meist schneller als ein Cursor.
  • Die Schnittstelle gibt es in allen modernen Browsern, auch in Web Workern. Im privaten Modus älterer Safari- und Firefox-Versionen kann IndexedDB eingeschränkt sein.