Signatur
Beschreibung
add() legt einen neuen Datensatz in einem IDBObjectStore an. Der übergebene Wert wird per Structured-Clone-Algorithmus kopiert und asynchron gespeichert. Zurückgegeben wird sofort ein IDBRequest. Dessen success-Ereignis liefert in request.result den Schlüssel des neuen Datensatzes.
Anders als put() überschreibt add() niemals etwas: Gibt es den Schlüssel im Store schon, scheitert die Anfrage mit einem ConstraintError. Das Gleiche passiert, wenn ein Index mit unique: true verletzt wird. Nimm add() also immer dann, wenn doppelte Einträge ein Fehler sind, etwa bei Registrierungen, Importen oder eindeutigen Kennungen.
Wie der Schlüssel bestimmt wird, hängt vom Store ab:
- Mit
keyPath(Inline-Schlüssel): Der Schlüssel steht im Objekt selbst. Das Argumentkeydarf dann nicht übergeben werden. - Ohne
keyPath(Out-of-line-Schlüssel): Der Schlüssel muss als zweites Argument übergeben werden, außer der Store nutztautoIncrement. - Mit
autoIncrement: Fehlt ein Schlüssel, erzeugt der Key-Generator eine fortlaufende Nummer. Bei einemkeyPathwird sie zusätzlich in das Objekt geschrieben.
Die Methode funktioniert nur innerhalb einer Transaktion im Modus "readwrite". Ein Fehler bei einer einzelnen Anfrage bricht standardmäßig die ganze Transaktion ab. Das lässt sich im error-Handler mit event.preventDefault() verhindern.
Parameter
| Name | Typ | Default | Beschreibung |
|---|---|---|---|
| $value Pflicht | any (strukturiert klonbar) | Der zu speichernde Wert. Er muss sich mit dem Structured-Clone-Algorithmus kopieren lassen: Objekte, Arrays, Date, Map, Set, Blob, File, ArrayBuffer usw. Funktionen und DOM-Knoten gehen nicht. |
|
| $key | IDBValidKey (number | string | Date | ArrayBuffer | Array) | Schlüssel des Datensatzes. Nur für Stores ohne keyPath erlaubt. Pflicht, wenn der Store weder keyPath noch autoIncrement hat. |
Rückgabewert
IDBRequest. Nach dem success-Ereignis enthält result den Schlüssel des neu angelegten Datensatzes. Schlägt die Anfrage fehl, enthält error eine DOMException, z. B. ConstraintError.Beispiele
Datensatz mit autoIncrement anlegen
const openReq = indexedDB.open('notizen-db', 1);
openReq.onupgradeneeded = () => {
const db = openReq.result;
db.createObjectStore('notizen', { keyPath: 'id', autoIncrement: true });
};
openReq.onsuccess = () => {
const db = openReq.result;
const tx = db.transaction('notizen', 'readwrite');
const store = tx.objectStore('notizen');
const req = store.add({ titel: 'Einkaufen', erstellt: new Date() });
req.onsuccess = () => console.log('Neue ID:', req.result);
tx.oncomplete = () => console.log('Transaktion abgeschlossen');
};
Doppelte Schlüssel abfangen (ConstraintError)
// Store 'nutzer' mit keyPath 'email'
const nutzerAnlegen = (db, nutzer) => {
const tx = db.transaction('nutzer', 'readwrite');
const req = tx.objectStore('nutzer').add(nutzer);
req.onerror = (event) => {
if (req.error.name === 'ConstraintError') {
console.warn(`E-Mail ${nutzer.email} ist bereits registriert`);
event.preventDefault(); // Transaktion nicht abbrechen
}
};
req.onsuccess = () => console.log('Angelegt:', req.result);
};
// nutzerAnlegen(db, { email: 'anna@example.com', name: 'Anna' });
// nutzerAnlegen(db, { email: 'anna@example.com', name: 'Anna B.' });
Promise-Wrapper mit Out-of-line-Schlüssel
const addAsync = (db, storeName, value, key) =>
new Promise((resolve, reject) => {
const tx = db.transaction(storeName, 'readwrite');
const req = tx.objectStore(storeName).add(value, key);
req.onsuccess = () => resolve(req.result);
req.onerror = () => reject(req.error);
});
// Store 'einstellungen' ohne keyPath, Schlüssel wird separat übergeben
const speichern = async (db) => {
try {
const key = await addAsync(db, 'einstellungen', { dunkel: true }, 'theme');
console.log('Gespeichert unter', key);
} catch (err) {
console.error(err.name, err.message);
}
};
// Wichtig · Fallstricke
add()oderput():add()scheitert, wenn der Schlüssel schon existiert. Für „einfügen oder aktualisieren“ nimmput().- Synchron geworfene Ausnahmen, also noch vor dem Request:
ReadOnlyError: Die Transaktion ist nicht"readwrite".TransactionInactiveError: Die Transaktion ist schon beendet, oft weil nach einemawaitauf etwas anderes als eine IndexedDB-Anfrage weitergearbeitet wurde.DataError: Der Schlüssel ist ungültig, fehlt, obwohl er Pflicht ist, oder wurde trotzkeyPathübergeben.DataCloneError: Der Wert lässt sich nicht klonen, z. B. weil er Funktionen enthält.InvalidStateError: Der Store wurde gelöscht.
- Transaktions-Lebensdauer: Zwischen Anfragen derselben Transaktion keine fremden asynchronen Operationen wie
fetchodersetTimeouteinschieben. Sonst schließt sich die Transaktion automatisch. - Fehler brechen die Transaktion ab: Ein nicht behandelter
ConstraintErrormacht alle Änderungen der Transaktion rückgängig. Das ist beim Massenimport wichtig. - Speicher: Wird das Kontingent überschritten, entsteht ein
QuotaExceededError. Im privaten Modus mancher Browser ist IndexedDB eingeschränkt. - IndexedDB wird von allen modernen Browsern und in Web Workern unterstützt, nicht jedoch in Node.js ohne Polyfill (z. B.
fake-indexeddb).