smart | Webentwicklung
Alles rund um HTML5, PHP, WordPress & Co.

HTML5 IndexedDB: Index erstellen und Daten suchen & filtern

10. Juni 2013
Stephan
HTML5 IndexedDB API: Index zum Suchen und Filtern von Daten nutzen

Wie in meinem Einführungsartikel zur HTML5 IndexedDB API beschrieben, handelt es sich bei der IndexedDB um keine relationale Datenbank. Somit können wir auch nicht einfach mittels einer SQL-Anfrage Datensätze, die bestimmte Bedingungen erfüllen sollen, auswählen und aus der Datenbank holen.

Stattdessen müssen wir umdenken und im Kontext der indexbasierten Datenbank Indizes in Verbindung mit Cursor verwenden, um gezielt Datensätze in einem Objektspeicher zu suchen und zu filtern.

Der folgende Artikel zeigt euch nun, wie ihr einen Index erstellen und nutzen könnt.

Beispiel: Speicherung von Personendaten

Als Beispiel soll uns ein Objektspeicher dienen, der zum Speichern von Personen-Objekten dient. Dabei wollen wir für eine Person den Namen, das Alter, den Wohnort und die E-Mail-Adresse speichern.

Zum einen möchten wir nun die Möglichkeit haben eine Person anhand ihrer (eindeutigen) E-Mail-Adresse aus dem Objektspeicher bzw. aus der Datenbank laden. Zum anderen soll es möglich sein, die Personen auszuwählen, die ein bestimmtes Alter haben und in einem bestimmten Wohnort leben.

Index für einen Objektspeicher erstellen

Bei einem Index handelt es sich auch um einen Objektspeicher. Wie Objektspeicher lassen sich Indizes somit auch nur innerhalb des onupgradeneeded-Event-Handlers erstellen.

Die Erstellung der Datenbank, des Objektspeichers, der Indizes und dem Hinzufügen von Beispieldaten findet ihr im Folgenden:

var db;

var openDbRequest = window.indexedDB.open('MyDB');

openDbRequest.onsuccess = function()
{
	db = openDbRequest.result;
	
	findByEmail('lisa@stadel.de');
	findByAgeAndLocation(22, 'Berlin');
}

openDbRequest.onupgradeneeded = function()
{
	db = openDbRequest.result;

	var objectStore = db.createObjectStore(
		'persons',
		{
			keyPath: 'id',
			autoIncrement: true
		}
	);
		

	objectStore.createIndex('byEmail', 'email', {unique: true});
	objectStore.createIndex('byAgeAndLocation', ['age', 'location'], {unique: false});
	
	objectStore.put(
	{
		name: 'Tom Maier', 
		email: 'tom@maier.de', 
		age: 22, 
		location: 'Berlin'
	});
	
	objectStore.put(
	{
		name: 'Lisa Stadel', 
		email: 'lisa@stadel.de', 
		age: 21, 
		location: 'München'
	});
	
	objectStore.put(
	{
		name: 'Bill Muster', 
		email: 'bill@muster.de', 
		age: 22, 
		location: 'Berlin'
	});
}

Aus Gründen der Übersichtlichkeit haben ich in diesem Fall mal auf die Implementierung der einzelnen onerror-Event-Handler verzichtet.

Für uns wichtig bzw. interessant sind bei diesem Code die Zeilen 26 und 27. Hier erstellen wir nämlich unsere Indizes. Ein Objektspeicher kann grundsätzlich mehrere Indizes haben, die mittels der createIndex-Funktion erstellt werden.

Als ersten Parameter geben wir dabei den Namen des Index an. Mit dem zweiten Parameter legen wir fest für welche Eigenschaftswerte der Index gilt. Um weitere optionale Einstellungen vorzunehmen, dient der dritte Parameter, den ich hier jetzt aber mal vernachlässige und nicht näher erläutere.

Person per E-Mail finden & auswählen

Um nun eine Person anhand ihrer E-Mail-Adresse zu finden, gibt es zwei Wege. Der erste und nicht gerade effiziente und schnelle Weg ist den ganzen Objektspeicher mit einen Cursor zu durchlaufen. In jedem Cursor-Schritt würden wir dann schauen, ob die E-Mail des aktuellen Personen-Objekts mit der angegebenen übereinstimmt. Wenn das der Fall ist, geben wir das gefundene Personen-Objekt zurück.

Aus Performancesicht viel besser ist die Verwendung unseres byEmail-Index. Dazu implementieren wir nun die im vorherigen Code-Auszug in Zeile 9 aufgerufene findByEmail-Funktion:

function findByEmail(email)
{
	var transaction = db.transaction('persons');

	var index = transaction.objectStore('persons').index('byEmail');

	var request = index.get(email);

	request.onsuccess = function()
	{
		console.log(request.result);
	}
}

Ansatt also mit dem eigentlichen Objektspeicher zu arbeiten, greifen wir auf den byEmail-Index zu (Zeile 5). Der get-Funktion des Index-Objekts können wir dann die E-Mail-Adresse übergeben und somit das entsprechende Personen-Objekt auswählen.

Im Bereich der relationalen Datenbanken könnte eine entsprechende SQL-Anfrage z.B. so aussehen:

SELECT *
FROM persons
WHERE email = 'lisa@stadel.de'

Personen per Alter & Wohnort finden & auswählen

Etwas komplexer wird es, wenn wir auf Basis mehrerer Eigenschaftswerte eines Objekts Datensätze bzw. Personen-Objekte auswählen möchten. In diesem Fall müssen wir einen Cursor nutzen:

function findByAgeAndLocation(age, location)
{
	var transaction = db.transaction('persons');

	var index = transaction.objectStore('persons').index('byAgeAndLocation');
	
	var keyRange = IDBKeyRange.only([age, location])

	var request = index.openCursor(keyRange);
	
	var persons = [];

	request.onsuccess = function()
	{
		var cursor = request.result;
		
		if(cursor)
		{
			persons.push(cursor.value);
			cursor.continue();
		}
		else
		{
			console.log(persons);
		}
	}
}

In diesem Fall greifen wir auf den erstellten byAgeAndLocation-Index zu (Zeile 5). Anschließend erzeugen wir ein KeyRange-Objekt und übergeben ein Array mit dem entsprechenden Alter und Wohnort (Zeile 7). Dieses KeyRange-Objekt wiederum übergeben wir der openCursor-Funktion.

Im Anschluss können wir nun mit unserem Cursor alle Datensätze durchlaufen, die das angegebene Alter und den angegebenen Wohnort haben.

Das Ganze dann mal als SQL-Anfrage:

SELECT *
FROM persons
WHERE age = 22 AND location = 'Berlin'

Fazit

Die HTML5 IndexedDB API unterstützt zwar kein SQL und somit keine SELECT-Anfragen, aber trotzdem lassen sich mithilfe von Indizes Datensätze gezielt durchsuchen und filtern.

Habt ihr schon mit Indizes im Rahmen der HTML5 IndexedDB API gearbeitet? Wie findet ihr die Möglichkeit, auf diese Weise Datensätze zu filtern?

Kommentare  
0 Kommentare vorhanden
0 Trackbacks/Pingbacks vorhanden
Du bist herzlich eingeladen auch ein Kommentar zu hinterlassen!
Kommentar schreiben

Vielen Dank für dein Kommentar!