Signatur
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
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();
};
};
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));
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');
// Wichtig · Fallstricke
- Transaktion läuft ab: Rufen Sie
continue()oderadvance()synchron imsuccess-Handler auf. Wenn Sie dazwischen etwa mitawait fetch()warten, schließt sich die Transaktion automatisch, und der nächste Aufruf wirftTransactionInactiveError. - Nur ein Schritt pro Ereignis: Wird
continue()zweimal im selben Durchlauf aufgerufen, kommt es zu einemInvalidStateError. update()unddelete()funktionieren nur inreadwrite-Transaktionen, sonst wirft der BrowserReadOnlyError. Bei Stores mitkeyPathdarfupdate()den Primärschlüssel nicht ändern, sonst folgt einDataError.valueist eine Kopie. Direkte Änderungen daran werden nur mitupdate()gespeichert.- Für reine Schlüssellisten ist
openKeyCursor()sparsamer, weil der Browser keine Werte deserialisieren muss. Für kleine Datenmengen sindgetAll()undgetAllKeys()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.