senäh

17senäh und so…

HTML/CSS/JS
21. Okt 2013
Kommentare: 0

MongoDB

Kategorien: HTML/CSS/JS | 21. Okt 2013 | Kommentare: 0

Serie: Einführung in den MEAN Stack

Bisher hat unser Server nur statische Daten zurückgeschickt: Dateien von der Festplatte oder im Quellcode hinterlegte Texte. Um Daten dynamisch einzubinden wird im MEAN Stack die NoSQL-Datenbank MongoDB verwendet. Im heutigen Artikel erkläre ich euch den Begriff NoSQL und wie ihr MongoDB mit Node verwendet.

Die Definition einer NoSQL-Datenbank ist etwas schwammig. Das „No“ steht nicht für „nicht“, sondern für „Not only“, also „Nicht nur SQL-Datenbanken“. Der Begriff wurde mit dieser Bedeutung 2009 von Johan Oskarsson eingeführt, um damit alle nicht-relationalen Datenbanken zu bezeichnen. Die Architektur von nicht-relationalen Datenbanken kann jedoch sehr unterschiedlich ausfallen, sodass eine weitere Unterteilung nötig wird. MongoDB gehört dabei zur Gruppe der dokumentenorientierten Datenbanken. Dabei sind Dokumente, deren Struktur frei festgelegt werden können, die Daten, welche in der Datenbank gespeichert werden. (Im Vergleich dazu speichert MySQL Daten in Tabellen ab.)

Die Dokumente von MongoDB werden im sogenannten BSON-Format gespeichert, einem JSON-ähnlichem Binärformat. Abfragen an die Datenbank werden in JavaScript durchgeführt. MongoDB ist übrigens die verbreitetste NoSQL-Datenbank.

Während MongoDB auch über den Terminal gesteuert werden kann, überspringt diese Artikelserie diesen Schritt und zeigt ohne Umwege die Verwendung von MongoDB mit Node. Lediglich zum Starten von MongoDB benötigen wir einmalig den Terminal:

$ mongod

Nachdem MongoDB initialisiert wurde, installieren wir in einem neuen Projektordner Express zusammen mit dem offiziellen MongoDB-Driver für Node. Um mehrere Module auf einmal mit npm herunterzuladen müssen lediglich mehrere Modulnamen aufgelistet werden:

$ npm install express mongodb

Nun sind Express und der MongoDB-Driver installiert. Für das folgende Beispiel – wir schrieben wieder alles in eine server.js-Datei – teilen wir den Quellcode in zwei Teile. Im ersten Teil erstellen wir eine Verbindung zu unserer MongoDB-Datenbank und legen eine Collection an. Eine Collection ist eine Gruppe von zusammengehörigen Dokumenten. In unserem Beispiel wollen wir die Besuche unserer Webseite speichern, deswegen nennen wir die Collection visitsCollection:

var MongoClient = require('mongodb').MongoClient;
var visitsCollection;
MongoClient.connect('mongodb://localhost:27017/first-db', function(err, db) {
  if(err)
    console.log(err);
  else
    visitsCollection = db.collection('visits');
});

In der ersten Zeile laden wir das Modul mongodb, von welchem wir den MongoClient benötigen. In der zweiten Zeile deklarieren wir die zuvor erwähnte Variable visitsCollection, welche wir später noch benötigen. Anschließend stellen wir über MongoClient eine Verbindung zu unserer Datenbank her. Die URL mongodb://localhost:27017/ ist Default-URL zu einer lokalen MongoDB-Installation. Der Suffix first-db ist der Name unser Datenbank. Moment! Wir haben doch noch gar keine Datenbank mit diesem Namen erstellt. Wie sollen wir dann eine Verbindung zu dieser herstellen? Das ist kein Problem. MongoDB erstellt eine Datenbank mit diesem Namen automatisch, wenn sie zum ersten Mal angefordert wird. Nach der URL wird als zweiter Parameter ein Callback übergeben. An diesem erkennt man ein typisches Muster von Node: Callbacks übergeben häufig zwei Parameter, wobei der erste Parameter ein Fehlerobjekt ist und der zweite Parameter das eigentliche Ergebnis. Anschließend kann schnell überprüft werden, ob ein Fehler aufgetreten ist, um diesen entsprechend auszugeben und abzufangen. Das eigentliche Ergebnis dieses Callbacks ist ein db-Objekt, welches eine API zu unserer Datenbank offenlegt. Wenn kein Fehler aufgetreten ist, möchten wir über db einen Zugang zu unserer Collection visits erhalten, welchen wir in die Variable visitsCollection speichern. Auch bei Collections gilt: Wir müssen vorher keine Collection mit dem Namen visits anlegen, MongoDB erstellt automatisch eine, wenn noch keine vorhanden ist.

Was wollen wir mit der Collection visits als nächsten tun? Sie sollen die Besucher unserer Webseite speichern. Zu diesem Zweck werden wir bei jedem Besuch eines Nutzers ein neues Dokument, d.h. einen neuen Datenbankeintrag, erstellen, welches die angeforderte URL und die Uhrzeit des Besuches enthält. Anschließend sollen alle bisherigen Besuche angezeigt werden. Um dies zu erreichen benötigen wir den zweiten Teil unseres Servers, welchen wir mit Express erstellen:

var express = require('express');
express()
  .get('*', function(req, res){
    var visit = {
      url: req.url,
      time: Date.now()
    };
    visitsCollection.insert(visit, function(err, doc) {
      visitsCollection.find().toArray(function(err, docs) {
        var log = '';
        docs.forEach(function(doc, index) {
          log += 'Visited ' + doc.url + ' on ' + doc.time + '.<br>';
        });
        res.send(log);
      });
    });
  })
  .listen(1337, '127.0.0.1');

Unser Server besteht aus einer einzigen Middleware, welche für die Route * gilt. Ein * ist ein spezieller Platzhalter von Express, welcher intern in einen regulären Ausdruck umgeschrieben wird. In diesem Fall steht * für jede beliebige URL! Egal über welche URL der Server angesprochen wird, die folgende Middleware wird immer ausgeführt. Zu Beginn der Middleware erstellen wir ein visit-Objekt mit der URL und der Zeit des Besuches. Dieses wird später exakt so in die Datenbank gespeichert. Die URL, die vom Nutzer angefordert wurde, kann über req.url abgefragt werden. Mit der Methode insert des visitsCollection-Objekts wird das visit-Objekt gespeichert. Die Methode erwartet als zweiten Parameter wieder einen Callback mit der Signatur eines Fehler- und eines Ergebnisobjekts. Nach dem speichern sollen über die Methode find des visitsCollection-Objekts alle gespeicherten Besuche abgefragt, in einem String namens log formatiert gespeichert und anschließend über res.send ausgeben werden. Dies gilt ebenfalls immer noch für jede beliebige URL, da wir uns noch in der gleichen Middleware befinden.

Besucht man nun http://127.0.0.1:1337/ so erhält man als Ausgabe „Visited /server on 1380190257203.“, wobei bei euch die Zeit anders sein wird. Testet nun verschiedene URLs wie http://127.0.0.1:1337/test/ oder http://127.0.0.1:1337/sddasd/. Ihr könnt auch einen anderen Browser verwenden oder den Node-Server zwischendurch neustarten. Die Daten bleiben erhalten und werden bei jedem Besuch erweitert. Eventuell fällt euch in einer Zeile auch die URL „/favicon.ico“ auf, die ihr wahrscheinlich nie selbst eingegeben habt. Das ist eine URL, welche die meisten Browser selbstständig aufrufen, um das sogenannte Favicon einer Seite herunterzuladen. Euer Ergebnis sollte ungefähr so aussehen:

MongoDB und Node im Einsatz

Die Verwendung des MongoDB-Drivers ist sehr einfach und intuitiv. Manchmal möchte man aber etwas mehr Kontrolle bei der Struktur der Dokumente haben. Für diesen Zweck kann man das Framework Mongoose einsetzen, welches ich euch im nächsten Artikel vorstelle.

Autor: Pipo

...kommt ursprünglich aus der Designerecke, ist aber im Laufe seines Studiums in die Webentwicklung gestolpert. Kann sich seit dem nicht so richtig entscheiden wo er hingehört und wagt deswegen vielleicht die Flucht nach vorne in ein komplett neues Gebiet. Vielleicht Management? Niemand weiß es. Auch er nicht.