Signatur
Beschreibung
IDBKeyRange steht für ein zusammenhängendes Intervall von Schlüsseln in der IndexedDB API. Ein solcher Bereich lässt sich überall übergeben, wo ein Schlüssel oder eine Abfrage erwartet wird, zum Beispiel an IDBObjectStore.get(), getAll(), count(), delete(), openCursor() und die entsprechenden Methoden von IDBIndex. So lassen sich gezielt nur die Datensätze lesen oder löschen, deren Schlüssel im Intervall liegen, ohne den ganzen Store zu durchlaufen.
Einen Konstruktor gibt es nicht. Instanzen entstehen über vier statische Fabrikmethoden:
IDBKeyRange.only(value): genau ein Schlüssel.IDBKeyRange.lowerBound(lower, open = false): alle Schlüssel ablower.IDBKeyRange.upperBound(upper, open = false): alle Schlüssel bisupper.IDBKeyRange.bound(lower, upper, lowerOpen = false, upperOpen = false): alle Schlüssel zwischen zwei Grenzen.
Die schreibgeschützten Eigenschaften lower, upper, lowerOpen und upperOpen geben die Grenzen an und ob sie ausgeschlossen („offen“) sind. Mit der Instanzmethode includes(key) prüft man, ob ein Schlüssel im Bereich liegt.
Verglichen wird nach der IndexedDB-Schlüsselreihenfolge: Number < Date < String < binäre Daten (ArrayBuffer/typisierte Arrays) < Array. Strings werden nach UTF-16-Codeeinheiten sortiert, nicht nach Sprachregeln (Locale). Mit Array-Schlüsseln lassen sich auch zusammengesetzte Indizes nach Bereichen abfragen.
Parameter
| Name | Typ | Default | Beschreibung |
|---|---|---|---|
| $lower Pflicht | any (gültiger IDB-Schlüssel) | Untere Grenze bei lowerBound() und bound(). Erlaubt sind number, string, Date, binäre Daten oder Array solcher Werte. |
|
| $upper Pflicht | any (gültiger IDB-Schlüssel) | Obere Grenze bei upperBound() und bound(). |
|
| $value Pflicht | any (gültiger IDB-Schlüssel) | Der einzige Schlüssel bei only(). |
|
| $lowerOpen | boolean | false | Bei true wird die untere Grenze ausgeschlossen. Bei lowerBound() heißt der Parameter open. |
| $upperOpen | boolean | false | Bei true wird die obere Grenze ausgeschlossen. Bei upperBound() heißt der Parameter open. |
Rückgabewert
IDBKeyRange-Objekt zurück. includes() gibt einen boolean zurück.Beispiele
Bereiche erzeugen und prüfen
const range = IDBKeyRange.bound(10, 20, false, true); // [10, 20)
console.log(range.lower, range.upper); // 10 20
console.log(range.lowerOpen, range.upperOpen); // false true
console.log(range.includes(10)); // true
console.log(range.includes(20)); // false
const single = IDBKeyRange.only('alice');
console.log(single.includes('alice')); // true
Bestellungen eines Zeitraums per Index laden
// Hilfsfunktion: IDBRequest in ein Promise verpacken
const promisify = (req) => new Promise((resolve, reject) => {
req.onsuccess = () => resolve(req.result);
req.onerror = () => reject(req.error);
});
const openDb = () => {
const req = indexedDB.open('shop', 1);
req.onupgradeneeded = () => {
const store = req.result.createObjectStore('orders', { keyPath: 'id' });
store.createIndex('byDate', 'date');
};
return promisify(req);
};
const getOrdersInMonth = async (year, month) => {
const db = await openDb();
const start = new Date(year, month - 1, 1);
const end = new Date(year, month, 1);
// Monatsanfang eingeschlossen, Folgemonat ausgeschlossen
const range = IDBKeyRange.bound(start, end, false, true);
const index = db.transaction('orders').objectStore('orders').index('byDate');
return promisify(index.getAll(range));
};
const orders = await getOrdersInMonth(2024, 3);
console.log(`${orders.length} Bestellungen im März 2024`);
Präfixsuche über Strings mit Cursor
const findByPrefix = (db, prefix) => new Promise((resolve, reject) => {
// '\uffff' als obere Grenze deckt alle Strings mit dem Präfix ab
const range = IDBKeyRange.bound(prefix, prefix + '\uffff');
const results = [];
const req = db.transaction('users').objectStore('users').openCursor(range);
req.onsuccess = () => {
const cursor = req.result;
if (cursor) {
results.push(cursor.value);
cursor.continue();
} else {
resolve(results);
}
};
req.onerror = () => reject(req.error);
});
// Aufruf: const users = await findByPrefix(db, 'ma');
Alte Einträge per Bereich löschen
const deleteOlderThan = (db, timestamp) => new Promise((resolve, reject) => {
const tx = db.transaction('logs', 'readwrite');
// Schlüssel = Zeitstempel; alles strikt unterhalb löschen
tx.objectStore('logs').delete(IDBKeyRange.upperBound(timestamp, true));
tx.oncomplete = () => resolve();
tx.onerror = () => reject(tx.error);
});
// await deleteOlderThan(db, Date.now() - 7 * 24 * 60 * 60 * 1000);
// Wichtig · Fallstricke
- Kein Konstruktor:
new IDBKeyRange()wirft einenTypeError. Verwende die statischen Methoden. - DataError:
bound()wirft eineDOMExceptionvom TypDataError, wennlower > upperist oder wenn beide Grenzen gleich sind und eine davon offen ist. Ungültige Schlüssel (undefined,null,boolean, Objekte,NaN, ungültigesDate) lösen ebenfalls einenDataErroraus. - Typreihenfolge: Zahlen und Strings werden nie gemischt verglichen.
IDBKeyRange.lowerBound(0)passt auch auf alle String-, Date- und Array-Schlüssel, weil diese in der Reihenfolge nach Zahlen kommen. Das kann zu unerwarteten Treffern führen. - String-Sortierung: Sortiert wird nach UTF-16-Codeeinheiten. Groß- und Kleinschreibung werden unterschieden (
'Z' < 'a'), und Umlaute folgen nicht dem deutschen Alphabet. - Zusammengesetzte Indizes: Bei Array-Schlüsseln wie
[kategorie, preis]filtert ein Bereich nur die erste Komponente sauber. Beispiel:bound(['buch', 0], ['buch', Infinity]). Mehrdimensionale Filter muss man selbst im Cursor erledigen. - Kompatibilität: Wird in allen modernen Browsern und in Web Workern unterstützt.
includes()gibt es erst seit etwa 2020 (Chrome 52, Firefox 47, Safari 10.1). In Node.js gibt es IndexedDB nur über Polyfills wiefake-indexeddb.