Mit IndexedDB arbeiten

In diesem Leitfaden werden die Grundlagen der IndexedDB API. Mit dem von Jake Archibald IndexedDB versprochen die dem IndexedDB API sehr ähnlich ist, aber Promise verwendet, Sie können await für eine kürzere Syntax. Dies vereinfacht die API und und die Struktur beibehalten.

Was ist IndexedDB?

IndexedDB ist ein umfangreiches NoSQL-Speichersystem, mit dem nur über alles im Browser der Nutzenden. Zusätzlich zu den üblichen Such-, Abruf- und put-Aktionen unterstützt, unterstützt IndexedDB auch Transaktionen und eignet sich gut für große Mengen strukturierter Daten speichern.

Jede IndexedDB-Datenbank ist für einen Ursprung eindeutig. (normalerweise die Websitedomain oder Subdomain), d. h., der Zugriff ist nicht möglich. irgendetwas anderem Ursprung. Die Limits für die Datenspeicherung normalerweise groß sind, wenn sie überhaupt vorhanden sind, aber unterschiedliche Browser und die Datenbereinigung unterscheiden. Im Abschnitt Weitere Informationen finden Sie erhalten Sie weitere Informationen.

IndexedDB-Begriffe

Datenbank
Die höchste Indexebene. Es enthält die Objektspeicher, die wiederum die Daten enthalten, die Sie dauerhaft speichern möchten. Sie können mehrere Datenbanken mit welchen Namen ihr wählt.
Objektspeicher
Ein einzelner Bucket zum Speichern von Daten, ähnlich wie Tabellen in relationalen Datenbanken. In der Regel gibt es einen Objektspeicher für jeden Typ (keine JavaScript-Daten). Typ) der Daten, die Sie speichern. Im Gegensatz zu Datenbanktabellen werden die JavaScript-Daten Datentypen in einem Speicher nicht einheitlich sein müssen. Wenn beispielsweise eine App einen people-Objektspeicher mit Informationen über drei Personen hat, können die Alters-Properties der Nutzer 53, 'twenty-five' und unknown sein.
Index
Eine Art von Objektspeicher zum Organisieren von Daten in einem anderen Objektspeicher Referenzobjektspeicher) durch eine einzelne Eigenschaft der Daten. Der Index wird verwendet, , um Datensätze im Objektspeicher nach dieser Eigenschaft abzurufen. Wenn Sie zum Beispiel oder Personen speichern, möchten Sie diese später vielleicht anhand ihres Namens, ihres Alters oder Lieblingstier.
Vorgang
Eine Interaktion mit der Datenbank.
Transaktion
Ein Wrapper um einen Vorgang oder eine Gruppe von Vorgängen, der die Datenbank stellt Integrität. Wenn eine der Aktionen in einer Transaktion fehlschlägt, wird keine der Aktionen ausgeführt. angewendet und die Datenbank kehrt in den Status zurück, in dem sie sich vor der Transaktion befand. begonnen. Alle Lese- oder Schreibvorgänge in IndexedDB müssen Teil einer Transaktion sein. Dies ermöglicht atomare Read-Change-Write-Vorgänge ohne Konfliktrisiko. und andere Threads, die gleichzeitig auf die Datenbank reagieren.
Cursor
Ein Mechanismus zum Iterieren über mehrere Datensätze in einer Datenbank.

IndexedDB-Unterstützung prüfen

IndexedDB wird fast allgemein unterstützt. Bei älteren Browsern ist es jedoch keine gute Idee, Funktionserkennung unterstützen. Am einfachsten ist es, wenn du dir die window ansiehst -Objekt enthält:

function indexedDBStuff () {
  // Check for IndexedDB support:
  if (!('indexedDB' in window)) {
    // Can't use IndexedDB
    console.log("This browser doesn't support IndexedDB");
    return;
  } else {
    // Do IndexedDB stuff here:
    // ...
  }
}

// Run IndexedDB code:
indexedDBStuff();

Datenbank öffnen

Mit IndexedDB können Sie mehrere Datenbanken mit beliebigen Namen erstellen. Wenn wenn man versucht, eine Datenbank zu öffnen, automatisch erstellt wird. Verwenden Sie zum Öffnen einer Datenbank die Methode openDB() aus der idb-Bibliothek:

import {openDB} from 'idb';

async function useDB () {
  // Returns a promise, which makes `idb` usable with async-await.
  const dbPromise = await openDB('example-database', version, events);
}

useDB();

Diese Methode gibt ein Promise zurück, das in ein Datenbankobjekt aufgelöst wird. Bei Verwendung des openDB()-Methode einen Namen, eine Versionsnummer und ein festzulegendes Ereignisobjekt an in der Datenbank arbeiten.

Hier ein Beispiel für die Methode openDB() im Kontext:

import {openDB} from 'idb';

async function useDB () {
  // Opens the first version of the 'test-db1' database.
  // If the database does not exist, it will be created.
  const dbPromise = await openDB('test-db1', 1);
}

useDB();

Setzen Sie die Prüfung auf IndexedDB-Unterstützung oben in der anonymen Funktion. Dieses beendet die Funktion, wenn der Browser IndexedDB nicht unterstützt. Wenn die Funktion wird die Methode openDB() aufgerufen, um eine Datenbank namens 'test-db1' zu öffnen. In diesem Beispiel wurde das optionale Ereignisobjekt weggelassen, damit einfach, aber Sie müssen sie angeben, um sinnvolle Arbeit mit IndexedDB auszuführen.

Mit Objektspeichern arbeiten

Eine IndexedDB-Datenbank enthält einen oder mehrere Objektspeicher, die jeweils über einen für einen Schlüssel und eine weitere Spalte für die mit diesem Schlüssel verknüpften Daten.

Objektspeicher erstellen

Eine gut strukturierte IndexedDB-Datenbank sollte einen Objektspeicher für jeden Typ haben die beibehalten werden müssen. Beispiel: Eine Website, die Nutzer*innen Profile und Notizen haben möglicherweise einen people-Objektspeicher, der person enthält. -Objekte und einen notes-Objektspeicher mit note-Objekten.

Um die Datenbankintegrität zu gewährleisten, können Sie Objektspeicher nur in der Event-Objekt in einem openDB()-Aufruf an. Das Ereignisobjekt stellt ein upgrade()-Objekt bereit. Methode, mit der Sie Objektspeicher erstellen können. Rufen Sie die Methode createObjectStore() innerhalb der Methode upgrade() zum Erstellen des Objektspeichers:

import {openDB} from 'idb';

async function createStoreInDB () {
  const dbPromise = await openDB('example-database', 1, {
    upgrade (db) {
      // Creates an object store:
      db.createObjectStore('storeName', options);
    }
  });
}

createStoreInDB();

Diese Methode verwendet den Namen des Objektspeichers und eine optionale Konfiguration -Objekt, mit dem Sie verschiedene Eigenschaften für den Objektspeicher definieren können.

Hier ein Beispiel für die Verwendung von createObjectStore():

import {openDB} from 'idb';

async function createStoreInDB () {
  const dbPromise = await openDB('test-db1', 1, {
    upgrade (db) {
      console.log('Creating a new object store...');

      // Checks if the object store exists:
      if (!db.objectStoreNames.contains('people')) {
        // If the object store does not exist, create it:
        db.createObjectStore('people');
      }
    }
  });
}

createStoreInDB();

In diesem Beispiel wird ein Ereignisobjekt an die Methode openDB() übergeben, um ein Objektspeicher. Wie zuvor ist die Erstellung des Objektspeichers abgeschlossen. in der Methode upgrade() des Ereignisobjekts. Da der Browser jedoch eine Fehlermeldung wenn Sie versuchen, einen bereits vorhandenen Objektspeicher zu erstellen, createObjectStore()-Methode in eine if-Anweisung verpacken, die Gibt an, ob der Objektspeicher vorhanden ist. Rufen Sie im if-Block Folgendes auf: createObjectStore(), um einen Objektspeicher mit dem Namen 'firstOS' zu erstellen.

So definieren Sie Primärschlüssel

Beim Definieren von Objektspeichern können Sie festlegen, wie Daten in mit einem Primärschlüssel. Sie können einen Primärschlüssel definieren, indem Sie entweder einen oder mit einem Schlüsselgenerator.

Ein Schlüsselpfad ist ein Attribut, das immer vorhanden ist und einen eindeutigen Wert enthält. Für Bei einem people-Objektspeicher können Sie z. B. die E-Mail-Adresse address als Schlüsselpfad:

import {openDB} from 'idb';

async function createStoreInDB () {
  const dbPromise = await openDB('test-db2', 1, {
    upgrade (db) {
      if (!db.objectStoreNames.contains('people')) {
        db.createObjectStore('people', { keyPath: 'email' });
      }
    }
  });
}

createStoreInDB();

In diesem Beispiel wird ein Objektspeicher mit dem Namen 'people' erstellt und dem Objekt email zugewiesen. bei der Option keyPath als Primärschlüssel verwenden.

Sie können auch einen Schlüsselgenerator wie autoIncrement verwenden. Der Schlüsselgenerator erstellt einen eindeutigen Wert für jedes Objekt, das dem Objektspeicher hinzugefügt wird. Standardmäßig Wenn Sie keinen Schlüssel angeben, erstellt IndexedDB einen Schlüssel und speichert ihn separat Daten zu extrahieren.

Im folgenden Beispiel wird ein Objektspeicher namens 'notes' erstellt und der Primärschlüssel, der automatisch als automatisch zunehmende Nummer zugewiesen wird:

import {openDB} from 'idb';

async function createStoreInDB () {
  const dbPromise = await openDB('test-db2', 1, {
    upgrade (db) {
      if (!db.objectStoreNames.contains('notes')) {
        db.createObjectStore('notes', { autoIncrement: true });
      }
    }
  });
}

createStoreInDB();

Das folgende Beispiel ähnelt dem vorherigen Beispiel, aber diesmal Der automatisch inkrementierende Wert wird explizit einer Property namens 'id' zugewiesen.

import {openDB} from 'idb';

async function createStoreInDB () {
  const dbPromise = await openDB('test-db2', 1, {
    upgrade (db) {
      if (!db.objectStoreNames.contains('logs')) {
        db.createObjectStore('logs', { keyPath: 'id', autoIncrement: true });
      }
    }
  });
}

createStoreInDB();

Die Auswahl der Methode zum Definieren des Schlüssels hängt von Ihren Daten ab. Wenn Ihr Daten eine Eigenschaft haben, die immer eindeutig ist, können Sie sie zur keyPath machen, um diese Einzigartigkeit zu erzwingen. Andernfalls verwenden Sie einen Wert mit automatischer Inkrementierung.

Mit dem folgenden Code werden drei Objektspeicher erstellt, die die verschiedenen Möglichkeiten Definition von Primärschlüsseln in Objektspeichern:

import {openDB} from 'idb';

async function createStoresInDB () {
  const dbPromise = await openDB('test-db2', 1, {
    upgrade (db) {
      if (!db.objectStoreNames.contains('people')) {
        db.createObjectStore('people', { keyPath: 'email' });
      }

      if (!db.objectStoreNames.contains('notes')) {
        db.createObjectStore('notes', { autoIncrement: true });
      }

      if (!db.objectStoreNames.contains('logs')) {
        db.createObjectStore('logs', { keyPath: 'id', autoIncrement: true });
      }
    }
  });
}

createStoresInDB();

Indexe definieren

Indexe sind eine Art von Objektspeicher, der zum Abrufen von Daten aus der Referenz verwendet wird. Objektspeicher durch eine angegebene Property. Ein Index befindet sich im Referenzobjekt gespeichert ist und dieselben Daten enthält, aber die angegebene Eigenschaft als Schlüsselpfad anstelle des Primärschlüssels des Referenzspeichers. Indizes müssen erstellt werden, wenn erstellen Sie Ihre Objektspeicher und können verwendet werden, um eine eindeutige Ihre Daten.

Rufen Sie zum Erstellen eines Index den createIndex() auf. -Methode für eine Objektspeicherinstanz:

import {openDB} from 'idb';

async function createIndexInStore() {
  const dbPromise = await openDB('storeName', 1, {
    upgrade (db) {
      const objectStore = db.createObjectStore('storeName');

      objectStore.createIndex('indexName', 'property', options);
    }
  });
}

createIndexInStore();

Diese Methode erstellt ein Indexobjekt und gibt es zurück. Die Methode createIndex() für Für die Instanz des Objektspeichers wird der Name des neuen Index als erste und das zweite Argument sich auf die Eigenschaft der Daten bezieht, -Index. Mit dem letzten Argument können Sie zwei Optionen definieren, der Index wird ausgeführt: unique und multiEntry. Wenn unique auf true gesetzt ist, gibt der Parameter lassen keine doppelten Werte für einen einzelnen Schlüssel zu. Als Nächstes: multiEntry legt fest, wie sich createIndex() verhält, wenn die indexierte Eigenschaft ein Array ist. Wenn auf true festgelegt ist, fügt createIndex() dem Index für jedes Array einen Eintrag hinzu. -Elements. Andernfalls wird ein einzelner Eintrag mit dem Array hinzugefügt.

Beispiel:

import {openDB} from 'idb';

async function createIndexesInStores () {
  const dbPromise = await openDB('test-db3', 1, {
    upgrade (db) {
      if (!db.objectStoreNames.contains('people')) {
        const peopleObjectStore = db.createObjectStore('people', { keyPath: 'email' });

        peopleObjectStore.createIndex('gender', 'gender', { unique: false });
        peopleObjectStore.createIndex('ssn', 'ssn', { unique: true });
      }

      if (!db.objectStoreNames.contains('notes')) {
        const notesObjectStore = db.createObjectStore('notes', { autoIncrement: true });

        notesObjectStore.createIndex('title', 'title', { unique: false });
      }

      if (!db.objectStoreNames.contains('logs')) {
        const logsObjectStore = db.createObjectStore('logs', { keyPath: 'id', autoIncrement: true });
      }
    }
  });
}

createIndexesInStores();

In diesem Beispiel haben die Objektspeicher 'people' und 'notes' Indexe. Bis Weisen Sie zum Erstellen der Indexe zuerst das Ergebnis von createObjectStore() (einem Objekt) zu. Objekt) in eine Variable zu übertragen, damit Sie createIndex() dafür aufrufen können.

Mit Daten arbeiten

In diesem Abschnitt wird beschrieben, wie Sie Daten erstellen, lesen, aktualisieren und löschen. Diese Operationen sind alle asynchron und verwenden Promise, wo die IndexedDB API -Anfragen. Dies vereinfacht die API. Anstatt auf Ereignisse zu warten, die durch der Anfrage haben, können Sie .then() für das Datenbankobjekt aufrufen, das vom openDB(), um Interaktionen mit der Datenbank zu starten, oder await ihre Erstellung.

Alle Datenvorgänge in IndexedDB werden innerhalb einer Transaktion ausgeführt. Jedes hat der Vorgang folgende Form:

  1. Datenbankobjekt abrufen.
  2. Transaktion in der Datenbank öffnen.
  3. Objektspeicher bei Transaktion öffnen.
  4. Vorgang für Objektspeicher ausführen.

Eine Transaktion kann als ein sicherer Wrapper um einen Vorgang oder eine Gruppe betrachtet werden. der Betriebsabläufe. Wenn eine der Aktionen innerhalb einer Transaktion fehlschlägt, für Aktionen wird ein Rollback durchgeführt. Transaktionen gelten für einen oder mehrere Objektspeicher, den Sie beim Öffnen der Transaktion definieren. Sie können schreibgeschützt sein und schreiben. Dieser Wert gibt an, ob die Operationen innerhalb der Transaktion den oder eine Änderung an der Datenbank vornehmen.

Daten erstellen

Rufen Sie zum Erstellen von Daten den add() auf. auf der Datenbankinstanz und übergeben Sie die Daten, die Sie hinzufügen möchten. Das add() Das erste Argument der Methode ist der Objektspeicher, dem die Daten hinzugefügt werden sollen. Der Das zweite Argument ist ein Objekt, das die gewünschten Felder und zugehörigen Daten enthält. hinzuzufügen. Hier ist das einfachste Beispiel, bei dem eine einzelne Datenzeile hinzugefügt wird:

import {openDB} from 'idb';

async function addItemToStore () {
  const db = await openDB('example-database', 1);

  await db.add('storeName', {
    field: 'data'
  });
}

addItemToStore();

Jeder add()-Aufruf findet innerhalb einer Transaktion statt. Selbst wenn das Promise aufgelöst wird, bedeutet das nicht unbedingt, dass der Vorgang funktioniert hat. Um sicherzustellen, der Hinzufügung ausgeführt wurde, müssen Sie überprüfen, Transaktion mit der Methode transaction.done() abgeschlossen. Dies ist ein Versprechen, das aufgelöst wird, wenn die Transaktion von selbst abgeschlossen wird, und ablehnt, wenn der Transaktionsfehler. Diese Prüfung muss für alle Schreibvorgänge durchgeführt werden, Betriebsabläufe denn nur so erfahren Sie, welche Änderungen an der Datenbank passiert ist.

Der folgende Code zeigt die Verwendung der Methode add() innerhalb einer Transaktion:

import {openDB} from 'idb';

async function addItemsToStore () {
  const db = await openDB('test-db4', 1, {
    upgrade (db) {
      if (!db.objectStoreNames.contains('foods')) {
        db.createObjectStore('foods', { keyPath: 'name' });
      }
    }
  });
  
  // Create a transaction on the 'foods' store in read/write mode:
  const tx = db.transaction('foods', 'readwrite');

  // Add multiple items to the 'foods' store in a single transaction:
  await Promise.all([
    tx.store.add({
      name: 'Sandwich',
      price: 4.99,
      description: 'A very tasty sandwich!',
      created: new Date().getTime(),
    }),
    tx.store.add({
      name: 'Eggs',
      price: 2.99,
      description: 'Some nice eggs you can cook up!',
      created: new Date().getTime(),
    }),
    tx.done
  ]);
}

addItemsToStore();

Nachdem Sie die Datenbank geöffnet (und bei Bedarf einen Objektspeicher erstellt haben) müssen Sie , um eine Transaktion durch Aufrufen der transaction()-Methode zu öffnen. Diese Methode ein Argument für den Store, für den Sie eine Transaktion durchführen möchten, sowie den Modus. In diesem Fall möchten wir an den Store schreiben. gibt 'readwrite' an.

Im nächsten Schritt fügen Sie dem Shop Artikel als Teil der Transaktion hinzu. Im vorherigen Beispiel haben wir drei Vorgänge für die 'foods' dass jeder ein Versprechen zurückgibt:

  1. Sie fügen einen Eintrag für ein leckeres Sandwich hinzu.
  2. Es wird ein Eintrag für ein paar Eier hinzugefügt.
  3. Signalisiert, dass die Transaktion abgeschlossen ist (tx.done).

Da all diese Aktionen versprochen werden, müssen wir warten, bis zum Ende. Die Übergabe dieser Versprechen an Promise.all ist eine praktische und ergonomische Art, dies zu erledigen. Promise.all akzeptiert ein Array von und endet, wenn alle Versprechen, die an sie übergeben wurden, gelöst sind.

Für die beiden hinzuzufügenden Datensätze hat die store-Schnittstelle der Transaktionsinstanz add() aufruft und die Daten an sie übergibt. Sie können den Promise.all-Anruf await sodass es nach Abschluss der Transaktion abgeschlossen wird.

Daten lesen

Rufen Sie zum Lesen von Daten den get() auf. auf der Datenbankinstanz, die Sie mit der Methode openDB() abrufen. get() übernimmt den Namen des Speichers und den Primärschlüsselwert des Objekts, das Sie die Sie abrufen möchten. Hier ein einfaches Beispiel:

import {openDB} from 'idb';

async function getItemFromStore () {
  const db = await openDB('example-database', 1);

  // Get a value from the object store by its primary key value:
  const value = await db.get('storeName', 'unique-primary-key-value');
}

getItemFromStore();

Wie bei add() gibt die Methode get() ein Promise zurück, sodass du es await oder verwende den .then()-Callback des Versprechens.

Im folgenden Beispiel wird die Methode get() für die Datenbank 'test-db4' 'foods', um eine einzelne Zeile mit dem Primärschlüssel 'name' abzurufen:

import {openDB} from 'idb';

async function getItemFromStore () {
  const db = await openDB('test-db4', 1);
  const value = await db.get('foods', 'Sandwich');

  console.dir(value);
}

getItemFromStore();

Das Abrufen einer einzelnen Zeile aus der Datenbank ist ziemlich einfach: offen Datenbank und geben Sie den Objektspeicher und den Primärschlüsselwert der Zeile an, Daten abrufen möchten. Da die Methode get() ein Promise zurückgibt, kannst du await.

Daten aktualisieren

Rufen Sie zum Aktualisieren von Daten den put() auf. im Objektspeicher. Die Methode put() ähnelt der Methode add() und kann auch anstelle von add() verwendet werden, um Daten zu erstellen. Hier ein einfaches Beispiel: wie Sie put() verwenden, um eine Zeile in einem Objektspeicher mit ihrem Primärschlüsselwert zu aktualisieren:

import {openDB} from 'idb';

async function updateItemInStore () {
  const db = await openDB('example-database', 1);

  // Update a value from in an object store with an inline key:
  await db.put('storeName', { inlineKeyName: 'newValue' });

  // Update a value from in an object store with an out-of-line key.
  // In this case, the out-of-line key value is 1, which is the
  // auto-incremented value.
  await db.put('otherStoreName', { field: 'value' }, 1);
}

updateItemInStore();

Wie andere Methoden gibt diese Methode ein Promise zurück. Sie können put() auch als Teil einer Transaktion ist. Hier ein Beispiel für den 'foods'-Shop der den Preis für das Sandwich und die Eier aktualisiert:

import {openDB} from 'idb';

async function updateItemsInStore () {
  const db = await openDB('test-db4', 1);
  
  // Create a transaction on the 'foods' store in read/write mode:
  const tx = db.transaction('foods', 'readwrite');

  // Update multiple items in the 'foods' store in a single transaction:
  await Promise.all([
    tx.store.put({
      name: 'Sandwich',
      price: 5.99,
      description: 'A MORE tasty sandwich!',
      updated: new Date().getTime() // This creates a new field
    }),
    tx.store.put({
      name: 'Eggs',
      price: 3.99,
      description: 'Some even NICER eggs you can cook up!',
      updated: new Date().getTime() // This creates a new field
    }),
    tx.done
  ]);
}

updateItemsInStore();

Wie Elemente aktualisiert werden, hängt davon ab, wie Sie einen Schlüssel festlegen. Wenn Sie eine keyPath festlegen, Jede Zeile im Objektspeicher ist mit einem Inline-Schlüssel verknüpft. Die vorherige Beispiel Zeilen basierend auf diesem Schlüssel aktualisiert. Wenn Sie Zeilen in diesem müssen Sie diesen Schlüssel angeben, um das entsprechende Element im Objektspeicher Sie können auch einen Out-of-Line-Schlüssel erstellen, indem Sie ein autoIncrement als Primärschlüssel.

Daten löschen

Rufe zum Löschen von Daten die delete() auf im Objektspeicher:

import {openDB} from 'idb';

async function deleteItemFromStore () {
  const db = await openDB('example-database', 1);

  // Delete a value 
  await db.delete('storeName', 'primary-key-value');
}

deleteItemFromStore();

Wie add() und put() können Sie auch diesen Teil einer Transaktion verwenden:

import {openDB} from 'idb';

async function deleteItemsFromStore () {
  const db = await openDB('test-db4', 1);
  
  // Create a transaction on the 'foods' store in read/write mode:
  const tx = db.transaction('foods', 'readwrite');

  // Delete multiple items from the 'foods' store in a single transaction:
  await Promise.all([
    tx.store.delete('Sandwich'),
    tx.store.delete('Eggs'),
    tx.done
  ]);
}

deleteItemsFromStore();

Die Struktur der Datenbankinteraktion ist dieselbe wie bei der anderen Geschäftsabläufe. Überprüfen Sie, ob die gesamte Transaktion abgeschlossen ist, indem Sie einschließlich der Methode tx.done in das Array, das Sie an Promise.all übergeben.

Alle Daten werden abgerufen

Bisher haben Sie jeweils nur Objekte aus dem Speicher abgerufen. Sie können auch alle Daten oder eine Teilmenge aus einem Objektspeicher oder -index mithilfe getAll()-Methode oder Cursors ein.

Die Methode getAll()

Die einfachste Möglichkeit, alle Daten eines Objektspeichers abzurufen, ist der Aufruf von getAll(). für den Objektspeicher oder -index erstellt:

import {openDB} from 'idb';

async function getAllItemsFromStore () {
  const db = await openDB('test-db4', 1);

  // Get all values from the designated object store:
  const allValues = await db.getAll('storeName');

  console.dir(allValues);
}

getAllItemsFromStore();

Diese Methode gibt alle Objekte im Objektspeicher ohne Einschränkungen zurück. überhaupt nicht. Dies ist die direkteste Methode, um alle Werte aus einem Objektspeicher abzurufen. aber auch am wenigsten flexibel ist.

import {openDB} from 'idb';

async function getAllItemsFromStore () {
  const db = await openDB('test-db4', 1);

  // Get all values from the designated object store:
  const allValues = await db.getAll('foods');

  console.dir(allValues);
}

getAllItemsFromStore();

In diesem Beispiel wird getAll() im Objektspeicher 'foods' aufgerufen. Dadurch werden alle Die Objekte aus 'foods', sortiert nach Primärschlüssel.

Cursor verwenden

Cursor bieten eine flexiblere Möglichkeit, mehrere Objekte abzurufen. Ein Cursor wählt eine in einem Objektspeicher oder Objektindex nach dem anderen in den Index aufnehmen, mit den Daten, wenn diese ausgewählt sind. Cursors, wie die anderen Datenbankvorgänge, Transaktionen.

Rufen Sie openCursor() auf, um einen Cursor zu erstellen. im Objektspeicher als Teil einer Transaktion. 'foods'-Speicher von vorherigen Beispielen gezeigt, wie ein Cursor durch alle Datenzeilen in Objektspeicher:

import {openDB} from 'idb';

async function getAllItemsFromStoreWithCursor () {
  const db = await openDB('test-db4', 1);
  const tx = await db.transaction('foods', 'readonly');

  // Open a cursor on the designated object store:
  let cursor = await tx.store.openCursor();

  // Iterate on the cursor, row by row:
  while (cursor) {
    // Show the data in the row at the current cursor position:
    console.log(cursor.key, cursor.value);

    // Advance the cursor to the next row:
    cursor = await cursor.continue();
  }
}

getAllItemsFromStoreWithCursor();

Die Transaktion wird in diesem Fall im 'readonly'-Modus geöffnet und openCursor-Methode wird aufgerufen. In einer nachfolgenden while-Schleife wird die Zeile bei Die aktuelle Position des Cursors kann die Eigenschaften key und value lesen und können Sie diese Werte so verwenden, wie es für Ihr Unternehmen Wenn Sie bereit sind, können Sie die continue() des cursor-Objekts aufrufen. um zur nächsten Zeile zu gelangen, und die while-Schleife endet, wenn der Cursor das Ende des Datasets erreicht.

Cursor mit Bereichen und Indexen verwenden

Mit Indizes können Sie die Daten in einem Objektspeicher anhand einer anderen Eigenschaft als der Primärschlüssel. Sie können für jedes Attribut einen Index erstellen, das zum keyPath wird für den Index, geben Sie einen Bereich für diese Eigenschaft an und rufen Sie die Daten innerhalb der mithilfe von getAll() oder einem Cursor.

Definieren Sie den Bereich mit dem Objekt IDBKeyRange. und einer der folgenden Methoden:

Die Methoden upperBound() und lowerBound() geben die oberen und unteren Grenzwerte an des Bereichs.

IDBKeyRange.lowerBound(indexKey);

Oder:

IDBKeyRange.upperBound(indexKey);

Sie verwenden jeweils ein Argument: den keyPath-Wert des Index für das gewünschte Element um es als Ober- oder Untergrenze festzulegen.

Die Methode bound() gibt sowohl eine Ober- als auch eine Untergrenze an:

IDBKeyRange.bound(lowerIndexKey, upperIndexKey);

Der Bereich für diese Funktionen ist standardmäßig inklusiv, d. h., er umfasst die als Grenzen des Bereichs angegebenen Daten. Wenn Sie diese Werte weglassen möchten, Sie legen den Bereich als exklusiv fest, indem Sie true als zweites Argument für übergeben. lowerBound() oder upperBound() oder als drittes und viertes Argument von bound() für die Unter- bzw. Obergrenze.

Im nächsten Beispiel wird ein Index für das Attribut 'price' im 'foods'-Objekt verwendet. speichern. An den Store ist jetzt auch ein Formular mit zwei Eingaben für die die Ober- und Untergrenzen des Bereichs. Verwende den folgenden Code, um Lebensmittel mit zwischen diesen Limits liegen:

import {openDB} from 'idb';

async function searchItems (lower, upper) {
  if (!lower === '' && upper === '') {
    return;
  }

  let range;

  if (lower !== '' && upper !== '') {
    range = IDBKeyRange.bound(lower, upper);
  } else if (lower === '') {
    range = IDBKeyRange.upperBound(upper);
  } else {
    range = IDBKeyRange.lowerBound(lower);
  }

  const db = await openDB('test-db4', 1);
  const tx = await db.transaction('foods', 'readonly');
  const index = tx.store.index('price');

  // Open a cursor on the designated object store:
  let cursor = await index.openCursor(range);

  if (!cursor) {
    return;
  }

  // Iterate on the cursor, row by row:
  while (cursor) {
    // Show the data in the row at the current cursor position:
    console.log(cursor.key, cursor.value);

    // Advance the cursor to the next row:
    cursor = await cursor.continue();
  }
}

// Get items priced between one and four dollars:
searchItems(1.00, 4.00);

Der Beispielcode ruft zuerst die Werte für die Grenzwerte ab und prüft, ob die Grenzwerte existieren. Der nächste Codeblock entscheidet, welche Methode zur Begrenzung des Bereichs verwendet wird. basierend auf den Werten. Öffnen Sie in der Datenbankinteraktion den Objektspeicher auf der Transaktion wie gewohnt und öffnen Sie dann den Index 'price' im Objektspeicher. Die Mit dem 'price'-Index können Sie nach Artikeln anhand des Preises suchen.

Der Code öffnet dann einen Cursor auf dem Index und übergibt den Bereich. Der Cursor gibt ein Promise zurück, das das erste Objekt im Bereich darstellt, oder undefined, wenn Der Bereich umfasst keine Daten. Die Methode cursor.continue() gibt eine Cursor, der das nächste Objekt darstellt, und setzt sich durch die Schleife, bis Sie bis das Ende des Bereichs erreicht ist.

Datenbankversionsverwaltung

Wenn Sie die Methode openDB() aufrufen, können Sie die Versionsnummer der Datenbank angeben im zweiten Parameter. Bei allen Beispielen in diesem Handbuch wurde die Version ist auf 1 festgelegt. Eine Datenbank kann jedoch bei Bedarf auf eine neue Version aktualisiert werden. irgendwie verändern. Wenn die angegebene Version höher ist als die Version von der vorhandenen Datenbank wird der Callback upgrade im Ereignisobjekt ausgeführt, sodass Sie der Datenbank neue Objektspeicher und Indexe hinzufügen können.

Das db-Objekt im upgrade-Callback hat eine spezielle oldVersion-Eigenschaft. die die Versionsnummer der Datenbank angibt, auf die der Browser Zugriff hat. Du kannst diese Versionsnummer an eine switch-Anweisung übergeben, um Blöcke auszuführen, Code im upgrade-Callback basierend auf der vorhandenen Datenbankversion Nummer. Beispiel:

import {openDB} from 'idb';

const db = await openDB('example-database', 2, {
  upgrade (db, oldVersion) {
    switch (oldVersion) {
      case 0:
        // Create first object store:
        db.createObjectStore('store', { keyPath: 'name' });

      case 1:
        // Get the original object store, and create an index on it:
        const tx = await db.transaction('store', 'readwrite');
        tx.store.createIndex('name', 'name');
    }
  }
});

In diesem Beispiel wird die neueste Version der Datenbank auf 2 festgelegt. Wenn dieser Code ausgeführt wird, ist die Datenbank noch nicht im Browser vorhanden, daher oldVersion ist 0 und die switch-Anweisung beginnt bei case 0. In diesem Beispiel fügt der Datenbank einen 'store'-Objektspeicher hinzu.

Wichtig: In switch-Anweisungen steht normalerweise ein break nach jedem case -Block, der hier absichtlich nicht verwendet wird. Wenn die vorhandenen oder wenn die Datenbank nicht existiert, wird der Code fortgesetzt. durch die restlichen case Blöcke, bis er auf dem neuesten Stand ist. In diesem Beispiel Der Browser fährt mit case 1 fort und erstellt einen name-Index auf der store-Objektspeicher.

Um einen 'description'-Index im 'store'-Objektspeicher zu erstellen, aktualisieren Sie den Versionsnummer und fügen Sie wie folgt einen neuen case-Block hinzu:

import {openDB} from 'idb';

const db = await openDB('example-database', 3, {
  upgrade (db, oldVersion) {
    switch (oldVersion) {
      case 0:
        // Create first object store:
        db.createObjectStore('store', { keyPath: 'name' });

      case 1:
        // Get the original object store, and create an index on it:
        const tx = await db.transaction('store', 'readwrite');
        tx.store.createIndex('name', 'name');

      case 2:
        const tx = await db.transaction('store', 'readwrite');
        tx.store.createIndex('description', 'description');
    }
  }
});

Wenn die im vorherigen Beispiel erstellte Datenbank noch im Browser vorhanden ist, wenn dies ausgeführt wird, ist oldVersion 2. Der Browser überspringt case 0 und case 1 und führt den Code in case 2 aus, wodurch ein description erstellt wird. -Index. Danach hat der Browser eine Datenbank mit Version 3, die ein store-Objekt enthält. Objektspeicher mit name- und description-Indexen.

Weitere Informationen

Die folgenden Ressourcen enthalten weitere Informationen und Kontext zur Verwendung von IndexedDB.

IndexedDB-Dokumentation

Beschränkungen für die Datenspeicherung