Start · Sprachen · JavaScript · Referenz · IDBKeyRange

IDBKeyRange

Schnittstelle

Beschreibt ein zusammenhängendes Schlüsselintervall in IndexedDB, mit dem Abfragen, Cursor und Löschvorgänge auf bestimmte Schlüssel eingegrenzt werden.

seit JavaScript Baseline: alle Browser (includes() seit 2020) Kategorie: webapi

Signatur

interface IDBKeyRange

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 ab lower.
  • IDBKeyRange.upperBound(upper, open = false): alle Schlüssel bis upper.
  • 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

Typ
IDBKeyRange
Beschreibung
Die statischen Fabrikmethoden geben ein neues, unveränderliches 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
10 20 false true true false 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`);
z. B. "12 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 einen TypeError. Verwende die statischen Methoden.
  • DataError: bound() wirft eine DOMException vom Typ DataError, wenn lower > upper ist oder wenn beide Grenzen gleich sind und eine davon offen ist. Ungültige Schlüssel (undefined, null, boolean, Objekte, NaN, ungültiges Date) lösen ebenfalls einen DataError aus.
  • 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 wie fake-indexeddb.