Signatur
Beschreibung
Das Interface IDBObjectStore steht für einen einzelnen Objektspeicher innerhalb einer IndexedDB-Datenbank – vergleichbar mit einer Tabelle in einer relationalen Datenbank. Jeder Datensatz besteht aus einem Schlüssel und einem Wert. Der Wert kann jedes per Structured Clone kopierbare Objekt sein (Objekte, Arrays, Date, Blob, Map usw.).
Objektspeicher legt man ausschließlich im upgradeneeded-Ereignis über IDBDatabase.createObjectStore() an. Danach kommt man über eine Transaktion an sie heran: db.transaction("name", "readwrite").objectStore("name"). Wichtige Eigenschaften sind name, keyPath, autoIncrement, indexNames und transaction.
Die wichtigsten Methoden:
add(value, key?)fügt einen Datensatz ein und schlägt fehl, wenn der Schlüssel schon existiert.put(value, key?)fügt ein oder überschreibt.get(key),getAll(query?, count?),getKey(),getAllKeys()undcount()lesen Daten.delete(keyOrRange)undclear()löschen Datensätze.openCursor()/openKeyCursor()laufen über Datensätze, auf Wunsch eingeschränkt durch einIDBKeyRange.createIndex(),deleteIndex()(nur während eines Upgrades) undindex(name)verwalten und nutzen sekundäre Indizes.
Alle Datenoperationen arbeiten asynchron und geben ein IDBRequest zurück. Das Ergebnis steht nach dem Ereignis success in request.result, Fehler kommen über error. Es gibt keinen Konstruktor, Instanzen bekommt man nur über createObjectStore() oder IDBTransaction.objectStore().
Parameter
| Name | Typ | Default | Beschreibung |
|---|---|---|---|
| $value Pflicht | any | Bei add()/put(): der zu speichernde Wert. Er muss per Structured Clone kopierbar sein, Funktionen und DOM-Knoten gehen also nicht. |
|
| $key | IDBValidKey | Bei add()/put(): ein expliziter Schlüssel. Er ist nicht erlaubt, wenn der Store einen keyPath hat, und Pflicht, wenn der Store weder keyPath noch autoIncrement hat. |
|
| $query | IDBValidKey | IDBKeyRange | Bei get(), getAll(), delete(), count() und openCursor(): ein einzelner Schlüssel oder ein Schlüsselbereich. |
|
| $count | number | unbegrenzt | Bei getAll()/getAllKeys(): die maximale Anzahl der gelieferten Datensätze. |
| $direction | "next" | "nextunique" | "prev" | "prevunique" | "next" | Bei openCursor()/openKeyCursor(): die Laufrichtung des Cursors. |
| $indexName, keyPath, options | string, string | string[], { unique?: boolean, multiEntry?: boolean } | Bei createIndex(): Name des Index, Pfad der indizierten Eigenschaft und Optionen (Eindeutigkeit, ein Indexeintrag je Array-Element). |
Rückgabewert
IDBRequest zurück, dessen result nach success das Ergebnis enthält (Wert, Schlüssel, Array, Anzahl oder IDBCursorWithValue). index() und createIndex() geben direkt einen IDBIndex zurück.Beispiele
Objektspeicher mit Index beim Upgrade anlegen
const openDb = () => new Promise((resolve, reject) => {
const req = indexedDB.open("shop", 1);
req.onupgradeneeded = () => {
const db = req.result;
// Objektspeicher mit keyPath und automatischem Schlüssel
const store = db.createObjectStore("products", { keyPath: "id", autoIncrement: true });
store.createIndex("by_sku", "sku", { unique: true });
store.createIndex("by_tags", "tags", { multiEntry: true });
console.log(store.name, store.keyPath, [...store.indexNames]);
};
req.onsuccess = () => resolve(req.result);
req.onerror = () => reject(req.error);
});
const db = await openDb();
Datensätze mit add, put und get bearbeiten (Promise-Hilfsfunktion)
const promisify = (req) => new Promise((resolve, reject) => {
req.onsuccess = () => resolve(req.result);
req.onerror = () => reject(req.error);
});
const tx = db.transaction("products", "readwrite");
const store = tx.objectStore("products");
const id = await promisify(store.add({ sku: "A-100", name: "Tasse", price: 9.9, tags: ["küche"] }));
await promisify(store.put({ id, sku: "A-100", name: "Tasse", price: 7.9, tags: ["küche", "sale"] }));
const product = await promisify(store.get(id));
console.log(id, product.price);
// Warten, bis die Transaktion abgeschlossen ist
await new Promise((res, rej) => { tx.oncomplete = res; tx.onerror = () => rej(tx.error); });
Über Index und Cursor abfragen
const store = db.transaction("products").objectStore("products");
// Alle Produkte mit dem Tag "sale" über den Index
const saleReq = store.index("by_tags").getAll("sale");
saleReq.onsuccess = () => console.log("Im Angebot:", saleReq.result.length);
// Cursor über die IDs 1 bis 100, absteigend
const cursorReq = store.openCursor(IDBKeyRange.bound(1, 100), "prev");
cursorReq.onsuccess = () => {
const cursor = cursorReq.result;
if (!cursor) return console.log("fertig");
console.log(cursor.key, cursor.value.name);
cursor.continue();
};
Bereich löschen und Einträge zählen
const tx = db.transaction("products", "readwrite");
const store = tx.objectStore("products");
store.delete(IDBKeyRange.lowerBound(50)); // alle IDs ab 50
const countReq = store.count();
countReq.onsuccess = () => console.log("Verbleibend:", countReq.result);