Dipl.-Math. Tobias Trelle ist Senior IT Consultant bei der code-centric AG, Solingen. Er ist seit knapp 20 Jahren im IT-Business unterwegs und interessiert sich für Softwarearchitekturen und skalierbare Lösungen. Zu diesen Themen veröffentlicht Tobias Artikel in Fachzeitschriften und hält Vorträge auf Konferenzen und Usergruppen. Außerdem organisiert er die Düsseldorfer MongoDB-Usergruppe.

Zu diesem Buch – sowie zu vielen weiteren dpunkt.büchern – können Sie auch das entsprechende E-Book im PDF-Format herunterladen. Werden Sie dazu einfach Mitglied bei dpunkt.plus+:

www.dpunkt.de/plus

MongoDB

Der praktische Einstieg

Tobias Trelle

Tobias Trelle

tobias.trelle@codecentric.de

Lektorat: René Schönfeldt

Copy-Editing: Sandra Gottmann, Münster

Herstellung: Birgit Bäuerlein

Umschlaggestaltung: Helmut Kraus, www.exclam.de

Druck und Bindung: M.P. Media-Print Informationstechnologie GmbH, 33100 Paderborn

Bibliografische Information der Deutschen Nationalbibliothek

Die Deutsche Nationalbibliothek verzeichnet diese Publikation in der Deutschen Nationalbibliografie; detaillierte bibliografische Daten sind im Internet über http://dnb.d-nb.de abrufbar.

ISBN

Buch 978-3-86490-153-9

PDF 978-3-86491-533-8

ePub 978-3-86491-534-5

1. Auflage 2014

Copyright © 2014 dpunkt.verlag GmbH

Wieblinger Weg 17

69123 Heidelberg

Die vorliegende Publikation ist urheberrechtlich geschützt. Alle Rechte vorbehalten. Die Verwendung der Texte und Abbildungen, auch auszugsweise, ist ohne die schriftliche Zustimmung des Verlags urheberrechtswidrig und daher strafbar. Dies gilt insbesondere für die Vervielfältigung, Übersetzung oder die Verwendung in elektronischen Systemen.

Es wird darauf hingewiesen, dass die im Buch verwendeten Soft- und Hardware-Bezeichnungen sowie Markennamen und Produktbezeichnungen der jeweiligen Firmen im Allgemeinen warenzeichen-, marken- oder patentrechtlichem Schutz unterliegen.

Alle Angaben und Programme in diesem Buch wurden mit größter Sorgfalt kontrolliert. Weder Autor noch Verlag können jedoch für Schäden haftbar gemacht werden, die in Zusammenhang mit der Verwendung dieses Buches stehen.

5 4 3 2 1 0

Für Vera und Kelian

Inhaltsverzeichnis

1      Einleitung

1.1      Big Data

1.2      NoSQL

1.3      Dokumentenorientierte Datenbanken

1.4      Verteilte Systeme und das CAP-Theorem

1.5      ACID vs. BASE

1.6      Zusammenfassung

2      MongoDB in 21 Minuten

2.1      Installation

2.2      Server starten

2.3      Mongo Shell

2.4      Erste Schritte

2.4.1      Collections

2.4.2      Dokumente

2.4.3      CRUD-Operationen

2.5      Daten importieren

2.6      Schemafreiheit

2.7      Zusammenfasssung

3      Grundlegende Konzepte

3.1      Konnektivität

3.2      Datenhaltung

3.3      Datenbanken

3.4      Collections

3.4.1      System Collections

3.4.2      Capped Collections

3.5      Dokumente

3.5.1      BSON

3.5.2      Datentypen

3.5.3      ObjectId

3.5.4      Primärschlüssel

3.5.5      Eingebettete Dokumente

3.5.6      Arrays

3.5.7      Dokumentreferenzen

3.6      Indizes

3.7      Namespaces

3.8      Abstraktionsebenen

3.9      Zusammenfassung

4      Replikation

4.1      Das Oplog

4.2      Master-Slave-Replikation

4.3      Replica Sets

4.3.1      Erste Schritte

4.3.2      Zugriff durch Anwendungen

4.3.3      Konfiguration im Detail

4.3.4      Grenzen der Replikation

4.4      Zusammenfassung

5      Sharding

5.1      Grundlagen

5.2      Der Schlüssel zum Sharding

5.3      Konfiguration

5.4      Fortgeschrittene Themen

5.4.1      Chunk-Verwaltung

5.4.2      Shards hinzufügen

5.4.3      Shards entfernen

5.4.4      Tag-basiertes Sharding

5.4.5      Produktive Sharding-Systeme

5.5      Zusammenfassung

6      Queries

6.1      Grundlegendes

6.2      Cursor

6.2.1      pretty()

6.2.2      limit()

6.2.3      skip()

6.2.4      sort()

6.2.5      batchSize()

6.2.6      objsLeftInBatch()

6.2.7      readPref()

6.2.8      snapshot()

6.2.9      showDiskLoc()

6.2.10      addOption()

6.3      Suchkriterien

6.3.1      Gleichheit

6.3.2      Logische Meta-Operatoren

6.3.3      Vergleichsoperatoren

6.3.4      Eingebettete Dokumente

6.3.5      Arrays

6.3.6      Reguläre Ausdrücke

6.3.7      $where

6.3.8      Schemafreiheit

6.3.9      Sonstiges

6.4      Indizes

6.4.1      Zusammengesetzte Indizes

6.4.2      Eingebettete Dokumente

6.4.3      Arrays

6.4.4      explain() und hint()

6.4.5      Covered Query

6.4.6      TTL-Index

6.4.7      Hashed Index

6.5      Profiling

6.5.1      Performance-Optimierung

6.5.2      Tools

6.6      Geodaten-Suche

6.6.1      Übersicht

6.6.2      Planare Koordinaten

6.6.3      Sphärische Koordinaten

6.7      Volltextsuche

6.7.1      Erstes Beispiel

6.7.2      Volltext-Indizes

6.7.3      Volltextsuche

6.7.4      Kombination mit anderen Suchkriterien

6.7.5      Sprachen und Stoppwortlisten

6.7.6      Negation und Suche nach Phrasen

6.7.7      Gewichtete Suche

6.7.8      Mehrsprachige Collections

6.8      Zusammenfassung

7      Manipulation von Dokumenten

7.1      Insert – Dokumente einfügen

7.1.1      Write Concern – der Konsistenzgrad

7.1.2      Mehrere Dokumente einfügen

7.2      Update – Änderungen an Dokumenten

7.2.1      Vollständige Ersetzung

7.2.2      Partielle Änderungen

7.2.3      Upsert – Anlegen und Ändern

7.2.4      FindAndModify – Suchen und Ändern

7.2.5      Änderungen an mehreren Dokumenten

7.2.6      Optimistisches Sperren

7.3      Save – Einfügen bzw. Ändern

7.4      Remove – Löschen von Dokumenten

7.5      Zusammenfassung

8      Schema-Design

8.1      Einleitung

8.2      Analyse und Modelle

8.2.1      Diagramme

8.2.2      Design by Example

8.3      Beziehungen

8.3.1      1:1-Beziehungen

8.3.2      1:n-Beziehungen

8.3.3      m:n-Beziehungen

8.4      Vererbung

8.5      Weitere Muster

8.5.1      Variable Dokumenteneigenschaften

8.5.2      Temporale Datenhaltung

8.5.3      Schema-Migration

8.6      Zusammenfassung

9      Aggregation von Daten

9.1      Abfragemethoden zur Datenaggregation

9.1.1      count()

9.1.2      distinct()

9.1.3      group()

9.2      Das Aggregation Framework

9.2.1      Grundkonzepte

9.2.2      Wie starte ich eine Aggregation?

9.2.3      Die Pipeline-Operatoren

9.2.4      Expressions

9.3      MapReduce

9.4      Zusammenfassung

10    Weiterführende Themen

10.1    GridFS

10.1.1      Zugriff über Treiber

10.2    REST-Schnittstelle

10.2.1      Server-Status ermitteln

10.2.2      Collections lesen

10.3    Sicherheit

10.3.1      Authentifizierung und Autorisierung

10.3.2      Netzwerk

10.4    Zusammenfassung

11    Softwareentwicklung mit MongoDB

11.1    Programmierbeispiele

11.1.1      Ruby

11.1.2      Java

11.2    Persistenz-Frameworks

11.2.1      Ruby

11.2.2      Java

11.3    Zusammenfassung

Anhang

A     Referenz der Kommandozeilenoptionen

A.1     Mongo – die Mongo Shell

A.2     mongod – Datenbank-Server

A.3     mongos – Router fürs Sharding

Index

1 Einleitung

1.1 Big Data

Sie wollen ein Buch über MongoDB lesen und werden als Erstes mit dem Begriff Big Data konfrontiert. Was hat MongoDB mit Big Data zu tun, werden Sie sich fragen. Was ist Big Data überhaupt genau? Um die Motivation zu verstehen, die zur Entstehung von MongoDB (und anderen nichtrelationalen Datenbanken) führte, will ich Ihnen zunächst eine Begriffsdefinition von Big Data geben.

Die grundlegenden technischen Herausforderungen im Big-Data-Umfeld wurden bereits 2001 von Doug Laney (heute Analyst bei Gartner) formuliert1 und sind heute unter der Abkürzung 3V bekannt. Dabei handelt es sich um die Aspekte:

Bei Volume geht es um die schiere Menge an Daten, die pro Zeiteinheit gespeichert werden muss.

Velocity adressiert die Geschwindigkeit, mit der die Daten persistiert, aber auch verarbeitet werden. Die Verarbeitung kann dabei im Batch oder aber auch in (Fast-)Echtzeit gewünscht sein.

Der Aspekt Variety bezieht sich auf die unterschiedlichen Grade von Strukturiertheit der Daten, das reicht von völlig unstrukturiert über semistrukturiert bis hin zu stark strukturiert.

Daneben machen zwei weitere Dinge den Begriff Big Data aus: Kostenersparnis durch elastische Skalierung und die Gewinnung neuer Informationen aus den Daten.

Ich möchte Ihnen folgende Fragen in Bezug auf Ihr relationales Datenbanksystem stellen. Haben Sie Probleme mit der Anzahl an schreibenden Operationen pro Sekunde? Wie schnell bzw. wie oft können und wollen Sie Ihre Reports erstellen? Wie gut passt Ihr logisches Datenmodell wirklich zum relationalen Modell?

Wenn Sie mit keinem dieser Aspekte oder ähnlich gelagerten Fragestellungen Probleme haben, dann haben Sie wahrscheinlich auch kein Big-Data-Problem. Stehen Sie aber vor einer oder allen diesen Herausforderungen, dann Sie sind sicherlich schon über den Begriff NoSQL gestolpert.

1.2 NoSQL

Der Begriff NoSQL2 ist keineswegs ein Imperativ, der zum vollständigen Boykott relationaler Datenbanksysteme aufruft. Er leitet sich ab von not only SQL, wobei SQL als Synonym für relationale Datenbankensysteme verwendet wird.

Die Grundidee ist die, dass man sich beim Umsetzen seiner konkreten Anforderungen (ob nun Big Data oder nicht) nicht im Vorhinein auf relationale Datenbanksysteme (RDBMS) beschränkt, nur weil man dies bei der Datenhaltung in den letzten Dekaden immer so getan hat. Riskieren Sie ruhig mal den Blick über den Tellerrand und setzen Sie das Datenbanksystem ein, das Ihr Problem optimal löst. Können Sie Ihr Problem am besten mit einer relationalen Datenbank lösen, dann tun Sie das auch und laufen nicht dem Hype hinterher.

Denn zum Einsatz von NoSQL-Technologien gehört Mut: Datenbankadministratoren haben wenig bis keine Erfahrung mit diesen neuartigen Technologien, Entwickler kennen die meist nichtstandardisierten APIs (noch) nicht. Das möchte ich mit diesem Buch in Bezug auf MongoDB ändern.

Entstanden sind die NoSQL-Datenbanken in der Web-2.0-Welt. Soziale Netzwerke wie Facebook, Twitter und Co. haben mit vielen Millionen, über den ganzen Globus verteilten Benutzern ganz andere Anforderungen an die Datenhaltung als das Bestandsführungssystem eines Versicherungsunternehmens. Es müssen sehr viele Daten sehr schnell gespeichert und abgerufen können. Dabei stoßen relationale Datenbanksysteme durchaus an ihre Grenzen, sowohl technologisch als auch vom Lizenzmodell her. Um eine fundierte Entscheidung bei der Auswahl der passenden NoSQL-Datenbank treffen zu können, ist natürlich – wie immer – Know-how gefragt, zumal sich in diesem Umfeld sehr viele Anbieter und auch Konzepte tummeln. Die wichtigsten Kategorien von NoSQL-Datenbanken3 sind:

Abbildung 1–1 zeigt einige der populärsten Vertreter:

Abb. 1–1 NoSQL-Datenbanken im Überblick

Relationale Datenbanksysteme sind Allzweckwaffen, die sich in der Regel auf eine große Menge von Problemen anwenden lassen. Im Gegensatz dazu stellen NoSQL-Datenbanken tendenziell eher Nischenlösungen dar, die bestimmte Probleme allerdings sehr viel besser lösen können.

1.3 Dokumentenorientierte Datenbanken

MongoDB gehört zur Kategorie der sogenannten dokumentenorientierten Datenbanken. Damit werden wir uns im weiteren Verlauf dieses Buches sehr detailliert auseinandersetzen. Ein Dokument ist ein einzelner Datensatz, der im Prinzip aus einer geordneten Liste von Key-Value-Paaren besteht und als Werte auch Arrays und eingebettete Dokumente zulässt. Ein Dokument kann man gut im JSON-Format darstellen, z. B. so:

{
       "name": "MongoDB",
       versionen: [
            { "major": 2, "minor": 6 },
            { "major": 2, "minor": 4 },
            { "major": 2, "minor": 2 }
       ]
}

Zur Speicherung verwendet MongoDB intern allerdings nicht das JSON-Format, sondern eine Abwandlung davon. Dazu aber später mehr. Mit diesem Datenformat adressiert MongoDB den Big-Data-Aspekt Variety: Ein Dokument eignet sich hervorragend zum Umgang mit semistrukturierten Daten, z. B. komplexen Vererbungshierarchien in OO-Sprachen. Aber auch für Volume und Velocity bietet MongoDB Lösungen an, auf die ich in den folgenden Kapiteln noch eingehen werde.

a. http://www.kchodorow.com/blog/2010/08/23/history-of-mongodb/

1.4 Verteilte Systeme und das CAP-Theorem

Den Big-Data-Aspekten Volume und Velocity ist in der Regel nur mit dem Einsatz von verteilten Systemen4 zu begegnen, in denen die Last und die Daten auf viele einzelne Rechnerknoten verteilt werden.

Aus dem CAP-Theorem (s. Kasten) folgt allerdings, dass man bei der Implementierung eines verteilten (Datenbank-)Systems nicht alle der Anforderungen an Konsistenz, Verfügbarkeit und Toleranz gegenüber Ausfällen gleichzeitig in vollem Maße erreichen kann.

Abb. 1–2 Veranschaulichung des CAP-Theorems

a. http://www.cs.berkeley.edu/~brewer/cs262b-2004/PODC-keynote.pdf

Die Auswirkungen des CAP-Theorems lassen sich gut an einem System veranschaulichen, das aus zwei Knoten besteht (s. Abb. 1–2). Das Netzwerk zwischen diesen Knoten soll gestört sein, sodass eine Partition des Systems in zwei Teile vorliegt, die sich gegenseitig nicht mehr erreichen können.

Erlaubt man nun einem der Knoten, seinen Zustand zu ändern (also im Falle eines Datenbanksystems schreibende Operationen auszuführen), wird das Gesamtsystem inkonsistent, man gibt also C auf. Will man die Konsistenz erhalten, muss der Knoten, dessen Zustand sich nicht ändert, sich als nicht verfügbar »abmelden« (da er sonst gegenüber den Clients einen nicht aktuellen Datenbestand ausliefern würde), womit man die Verfügbarkeit (A) des Systems auf nur noch einen Knoten reduziert. Nur wenn alle Knoten stets miteinander kommunizieren können, kann man dauerhaft C und A aufrecht erhalten, was dann offenbar im Widerspruch zu P steht.

Relationale Datenbanksysteme fallen in der Regel in die CA-Kategorie, da sie großen Wert auf die Konsistenz legen und auch hohe Verfügbarkeiten garantieren. Bei Systemen, die nur auf einem Knoten laufen, kann die Ausfallsicherheit durch den Kauf sehr teurer Hardware ebenfalls nah an die 100% gebracht werden. Fällt der eine Knoten aus, ist das System aber nicht mehr verfügbar. Bei Datenbank-Clustern verringert sich die Verfügbarkeit, da die Transaktionen zur Sicherstellung der Konsistenz auf mehreren Knoten eine längere Laufzeit haben.

Bei vielen NoSQL-Datenbanken kann man aufgrund der hohen Verteilung nicht auf die Partition Tolerance (P) verzichten. Da die Verfügbarkeit (A) ebenfalls einen sehr hohen Stellenwert einnimmt (da man grundsätzlich alle Anfragen an das System beantworten können möchte), bleibt nur der Ausweg, an der Konsistenz (C) zu sparen. Dies ist dann aber eine bewusste Design-Entscheidung beim Entwurf dieser Systeme und nicht dem Unwillen oder der Vergesslichkeit der Entwickler geschuldet.

Sie als Anwender solcher Technologien sollten sich aber stets bewusst sein, dass Sie sich nicht mehr auf Ihre bisherigen Konsistenzzusagen verlassen können!

1.5 ACID vs. BASE

Das ACID5-Prinzip, das Sie von relationalen Datenbanksystemen gewohnt sind, stellt in Zusammenhang mit Transaktionen6 Folgendes sicher:

  • Atomicity (Atomarität):

    Eine Transaktion wird nach dem Alles-oder-nichts-Prinzip entweder vollständig oder gar nicht ausgeführt. Wird eine atomare Transaktion abgebrochen, ist das System in einem unveränderten Zustand.

  • Consistency (Konsistenz):

    Eine Folge von Datenbankoperationen führt wieder zu einem konsistenten Zustand, sofern das System zuvor schon in einem konsistenten Zustand war. Hier bezieht sich die Konsistenz vorwiegend auf die inhaltliche und referenzielle Integrität7 des Datenbestandes.

  • Isolation:

    Nebenläufig ausgeführte Transaktionen beeinflussen sich nicht gegenseitig.

  • Durability (Dauerhaftigkeit):

    Die Auswirkungen von Transaktionen müssen dauerhaft im System gespeichert werden, insb. auch bei Systemabstürzen.

Bitte beachten Sie, dass der Konsistenzbegriff aus dem CAP-Theorem und dem ACID-Prinzip nicht identisch sind, sondern sich auf verschiedenen Granularitätsebenen bewegen.

NoSQL-Datenbanken können (oder wollen) eine Konsistenz im Sinne des ACID-Prinzips oft nicht garantieren, gewährleisten dann aber einen anderen Grad an Konsistenz. Hier kommt der Begriff BASE8 ins Spiel:

  • Basically Available
  • Soft State
  • Eventual Consistency

Dieses zugegebenermaßen sehr konstruiert wirkende Akronym will den Gegensatz zu ACID (im Englischen Säure) und BASE (Lauge) aus der Chemie aufgreifen. Die beiden Begriffe Basically Available und Soft State sind nicht präzise definiert, greifen aber nach meiner Interpretation die Verfügbarkeit (A) des CAP-Theorems auf.

Unter Eventual Consistency wird relativ klar das C des CAP-Theorems adressiert, und zwar in dem Sinne, dass das verteilte System (nach einer möglichst kurzen Zeitspanne der Inkonsistenz) letztendlich wieder in einem konsistenten Zustand ist.

Die letztendliche Konsistenz möchte ich an einem konkreten Beispiel mit zwei Knoten erläutern. Schreibzugriffe sind nur an einem der Knoten, den wir Master nennen, erlaubt. Der Master repliziert den Datenbestand in regelmäßigen Abständen an den anderen Knoten, den wir Slave nennen. Lesezugriffe sind an beiden Knoten erlaubt. Nach einem Schreibvorgang auf dem Master sehen Clients, die vom Slave lesen, die neuen oder geänderten Daten nicht sofort. Erst nach Abschluss der Replikation, die ggf. asynchron arbeitet, ist der Slave wieder auf dem aktuellen Stand.

Mit MongoDB können Sie keine Transaktionen fahren, die mehr als ein Dokument umfassen. Selbst bei Operationen auf nur einem Dokument ist kein explizites Rollback möglich. Immerhin sind Änderungen an einem Dokument aber atomar im Sinne des ACID-Prinzips. Da Sie ganze Objektnetze in einem Dokument unterbringen können, sind dokumentenübergreifende Transaktionen oft auch gar nicht notwendig.

1.6 Zusammenfassung

In dieser Einleitung haben Sie die Herausforderungen kennengelernt, die es im Big-Data-Umfeld zu meistern gilt. Sie haben ferner die Grundidee hinter der NoSQL-Bewegung verstanden und wissen, dass Sie insbesondere bei der Konsistenz umdenken müssen, wenn Sie MongoDB einsetzen.

Was Sie dabei beachten müssen, damit Sie dennoch keine Daten verlieren, werde ich Ihnen im Rest des Buches zeigen. Lassen Sie uns also jetzt direkt durchstarten in die Welt abseits des relationalen Pfades, in eine Welt ohne ACID, in die Welt von MongoDB ...

Fußnoten

Kapitel 1

1. http://blogs.gartner.com/doug-laney/deja-vvvue-others-claiming-gartners-volume-velocity-variety-construct-for-big-data/
2. http://de.wikipedia.org/wiki/NoSQL
3. Stefan Edlich pflegt eine sehr umfangreiche Liste mit NoSQL-Datenbanken: http://www.nosql-database.org/
4. http://de.wikipedia.org/wiki/Verteilte_Systeme
5. http://de.wikipedia.org/wiki/ACID
6. http://de.wikipedia.org/wiki/Transaktion_(Informatik)
7. http://de.wikipedia.org/wiki/Referentielle_Integrit%C3%A4t
8. http://en.wikipedia.org/wiki/Eventual_consistency

Kapitel 2

1. http://www.mongodb.org/display/DOCS/Quickstart
2. Intern verwendet die Mongo Shell Googles V8 JavaScript-Engine
3. Eine Auflistung aller Kommandozeilenparameter finden Sie im Anhang.
4. http://www.json.org/

Kapitel 3

1. http://www.mongodb.org/display/DOCS/Drivers
2. http://de.wikipedia.org/wiki/ACID#Dauerhaftigkeit
3. http://docs.mongodb.org/manual/reference/limits/
4. http://docs.mongodb.org/manual/reference/limits/
5. http://docs.mongodb.org/manual/reference/system-collections/
6. http://de.wikipedia.org/wiki/Warteschlange_%28Datenstruktur%29
7. http://bsonspec.org/
8. http://www.json.org/
9. http://de.wikipedia.org/wiki/UTF-8
10. http://de.wikipedia.org/wiki/Object-relational_impedance_mismatch
11. http://de.wikipedia.org/wiki/Datenbankindex

Kapitel 4

1. http://de.wikipedia.org/wiki/Replikation_(Datenverarbeitung)
2. http://de.wikipedia.org/wiki/Idempotenz
3. http://docs.mongodb.org/manual/tutorial/resync-replica-set-member/
4. http://aphyr.com/posts/284-call-me-maybe-mongodb

Kapitel 5

1. http://en.wikipedia.org/wiki/Sharding
2. http://de.slideshare.net/mongodb/advanced-sharding-features-in-mongodb-24/34
3. http://docs.mongodb.org/manual/core/sharded-cluster-architectures-production/
4. http://zookeeper.apache.org
5. http://www.puppetlabs.com

Kapitel 6

1. http://docs.mongodb.org/manual/reference/method/cursor.addOption/
2. http://de.wikipedia.org/wiki/Perl_Compatible_Regular_Expressions
3. http://de.wikipedia.org/wiki/Datenbankindex
4. http://www.tokutek.com/2013/05/sysbench-benchmark-for-mongodb-v0-1-0-performance-update/
5. http://docs.mongodb.org/manual/reference/method/cursor.explain/
6. http://docs.mongodb.org/manual/reference/command/collMod/
7. http://de.wikipedia.org/wiki/Hashing
8. http://docs.mongodb.org/manual/reference/database-profiler/
9. http://docs.mongodb.org/manual/reference/program/mongostat/
10. https://mms.mongodb.com/
11. https://github.com/mongolab/dex
12. https://github.com/idealo/mongodb-slow-operations-profiler
13. http://tomcat.apache.org/
14. http://www.geojson.org/geojson-spec.html
15. http://de.wikipedia.org/wiki/Sph%C3%A4rische_Geometrie
16. http://docs.mongodb.org/manual/reference/command/geoNear/
17. http://de.wikipedia.org/wiki/Sph%C3%A4rische_Geometrie
18. http://de.wikipedia.org/wiki/L%C3%A4ngengrad
19. http://de.wikipedia.org/wiki/Geographische_Breite
20. http://de.wikipedia.org/wiki/Stoppwort
21. http://de.wikipedia.org/wiki/Stemming
22. http://en.wikipedia.org/wiki/Phrase_search (keine dt. Übersetzung verfügbar)
23. http://lucene.apache.org/solr/
24. http://www.elasticsearch.org/
25. http://lucene.apache.org/

Kapitel 7

1. CRUD = Create, Read, Update, Delete (dt.: Anlegen, Lesen, Ändern, Löschen)
2. http://de.wikipedia.org/wiki/ACID#Dauerhaftigkeit
3. https://github.com/mongodb/mongo-java-driver/blob/master/src/main/com/mongodb/WriteConcern.java
4. http://de.wikipedia.org/wiki/ACID
5. http://de.wikipedia.org/wiki/Optimistisches_Locking
6. http://de.wikipedia.org/wiki/Lock

Kapitel 8

1. http://de.wikipedia.org/wiki/Schema_(Informatik)#Schemata_in_Datenbanksystemen
2. http://www.uml.org/
3. http://de.wikipedia.org/wiki/Impedance_Mismatch
4. http://de.wikipedia.org/wiki/Komposition_(UML)#Komposition
5. http://uml.org/
6. http://de.wikipedia.org/wiki/Kardinalit%C3%A4t_(Datenbankmodellierung)
7. http://de.wikipedia.org/wiki/Assoziation_(UML)#Assoziationsenden
8. http://de.wikipedia.org/wiki/Fremdschl%C3%BCssel#Fremdschl.C3.BCssel
9. http://de.wikipedia.org/wiki/Vererbung_(Programmierung)
10. https://github.com/mongodb/morphia
11. http://projects.spring.io/spring-data-mongodb/
12. http://de.wikipedia.org/wiki/Graphdatenbank
13. http://de.wikipedia.org/wiki/Temporale_Datenhaltung
14. http://de.wikipedia.org/wiki/Data_Access_Object
15. http://de.wikipedia.org/wiki/Repository_(Entwurfsmuster)

Kapitel 9

1. http://de.wikipedia.org/wiki/MapReduce
2. Prämierte amerikanische TV-Serie, http://de.wikipedia.org/wiki/Boardwalk_Empire
3. http://hadoop.apache.org/
4. Googles Veröffentlichung zu MapReduce ist auch heute immer noch sehr lesenswert und der interessierte Leser sollte sie sich nicht entgehen lassen: http://research.google.com/archive/mapreduce.html
5. http://de.wikipedia.org/wiki/Enron

Kapitel 10

1. http://docs.mongodb.org/manual/core/gridfs/
2. http://de.wikipedia.org/wiki/Representational_State_Transfer
3. http://curl.haxx.se/
4. http://docs.mongodb.org/manual/reference/user-privileges
5. http://de.wikipedia.org/wiki/Kerberos_(Informatik)
6. http://de.wikipedia.org/wiki/LDAP
7. Eine vollständige Liste finden Sie in der Online-Dokumentation: http://docs.mongodb.org/master/reference/privilege-actions/#security-user-actions
8. http://de.wikipedia.org/wiki/Tunnel_(Rechnernetz)
9. http://docs.mongodb.org/manual/tutorial/configure-ssl/
10. http://www.mongodb.org/about/contributors/#compiling-and-building-mongodb

Kapitel 11

1. http://www.mongodb.org/display/DOCS/Mongo+Wire+Protocol
2. http://www.mongodb.org/display/DOCS/Drivers
3. http://api.mongodb.org/ruby/current/file.TUTORIAL.html
4. http://de.wikipedia.org/wiki/RubyGems
5. http://www.mongodb.org/display/DOCS/Java+Tutorial
6. http://maven.apache.org/
7. http://www.gradle.org/
8. http://mongoid.org/en/mongoid/index.html
9. http://mongomapper.com/
10. http://de.wikipedia.org/wiki/Active_Record
11. http://projects.spring.io/spring-data-mongodb/
12. https://github.com/mongodb/morphia
13. http://jongo.org/
14. https://github.com/FasterXML/jackson

2 MongoDB in 21 Minuten

In diesem Kapitel zeige ich Ihnen, wie schnell Sie einen MongoDB-Server installieren, starten und benutzen können. Sie werden Testdaten importieren und Ihre ersten Abfragen absetzen.

2.1 Installation

Die jeweils aktuelle Version von MongoDB kann auf der Homepage heruntergeladen werden: http://www.mongodb.org/downloads. Sie sollten die stabile Produktionsversion verwenden. Ich werde die Installation exemplarisch für Windows durchführen, Anleitungen für andere Betriebssysteme können Sie der Online-Dokumentation1 entnehmen.

Nachdem die passende Archivdatei heruntergeladen ist, entpacke ich den Inhalt in ein Verzeichnis meiner Wahl, z. B. C:\nosql. Dort befindet sich nun ein neues Verzeichnis, dessen Name mit mongodb gefolgt von Betriebssystem- und Versionsinfos beginnt, z. B.:

c:\nosql\mongodb-win32-x86_64-2008plus-2.x

Auf dieses Verzeichnis werde ich mich im Folgenden als MONGO_HOME beziehen.

2.2 Server starten

Um den Server-Prozess zu starten, öffnen Sie eine Kommandozeilen-Shell und wechseln in das Verzeichnis MONGO_HOME\bin. Dort befinden sich alle ausführbaren Programme, die wir zum Betrieb und zur Administration eines MongoDB-Systems benötigen. Zunächst müssen wir noch ein neues Verzeichnis anlegen, in dem MongoDB seine Daten speichert:

rem Windows
mkdir \data

# Unix
mkdir /data

Anschließend starten wir den Server mit

mongod --dbpath /data

Auf der Konsole sollten nun in etwa folgende Log-Ausgaben zu sehen sein:

Sat Dec 01 14:15:40 [initandlisten] MongoDB starting : pid=5616 port=27017
dbpath=/data 64-bit host=localhost
Sat Dec 01 14:15:40 [initandlisten] db version v2.x, pdfile version 4.5
Sat Dec 01 14:15:40 [initandlisten] git version:
f5e83eae9cfbec7fb7a071321928f00d1b0c5207
Sat Dec 01 14:15:40 [initandlisten] build info: windows
sys.getwindowsversion(major=6, minor=1, build=7601, platform=2,
service_pack='Service Pack 1') BOOST_LIB_VERSION=1_49
Sat Dec 01 14:15:40 [initandlisten] options: { dbpath: "/data", rest: true }
Sat Dec 01 14:15:40 [initandlisten] journal dir=/data/journal
Sat Dec 01 14:15:40 [initandlisten] recover : no journal files present, no
recovery needed
Sat Dec 01 14:15:40 [initandlisten] waiting for connections on port 27017

Ohne weitere Konfiguration verwendet ein MongoDB-Server als Default den TCP/IP-Port 27017 für eingehende Verbindungen. Wenn Sie den Server mit der Kommandozeilenoption

$ mongod --httpinterface --rest

starten, können Sie 1000 Ports höher, also unter folgender URL:

http://localhost:28017

eine einfache, HTML-basierte Administrationsoberfläche erreichen (s. Abb. 2–1)

Abb. 2–1 Interface zur Administration

Dort finden sich Informationen über verbundene Clients, Datenbankoperationen und aufgetretene Locks, auf die wir im weiteren Verlauf des Buchs näher eingehen werden.

2.3 Mongo Shell

Im weiteren Verlauf werden wir die sogenannte Mongo Shell verwenden. Dabei handelt es sich um einen Kommandozeilen-Client, mit dem wir den Server administrieren und auch Daten manipulieren können.

Als Benutzer erhalten Sie einen Prompt, auf dem Sie JavaScript2-Befehle und -Skripte ausführen können. Dabei können Sie auf eine Reihe bestehender Java-Script-Objekte zugreifen, die jeweils bestimmte Datenbankkonstrukte repräsentieren. Aus Sicht des Servers verhält sich die in C++ implementierte Mongo Shell wie jeder andere Datenbank-Client.

Gestartet wird das Ganze im Verzeichnis MONGO_HOME/bin:

$ mongo3

Da der zuvor gestartete Server auf dem Standardport 27017 horcht, müssen wir keine weiteren Verbindungsparameter angeben. Danach werden wir von der Mongo Shell wie folgt begrüßt:

MongoDB shell version: 2.x
connecting to: test
>

Wenn wir beim Start der Mongo Shell keinen Namen einer Datenbank angeben, verwenden wir standardmäßig eine zunächst leere Datenbank namens test. Setzen Sie zum Einstieg ein paar einfache JavaScript-Befehle ab:

> var a = 2
> b = a + 2
4
> for (i=0; i<5; i++) { print(i) }
0
1
2
3
4

2.4 Erste Schritte

Ein MongoDB-Server verwaltet mehrere logische Datenbanken. Einen Überblick über alle Datenbanken verschaffen wir uns mit dem Befehl

> show dbs
local 0.078125GB

In einem frisch aufgesetzten System sehen wir nur die stets existierende Datenbank local.

Eine Übersicht über weitere Befehle erhalten Sie mit dem Kommando help().

2.4.1 Collections

Einzelne Datensätze, die in MongoDB Dokumente heißen, werden innerhalb logischer Namensräume organisiert, den sogenannten Collections. Eine Collection entspricht in etwa einer Tabelle aus einem relationalen Datenbanksystem, ist aber nicht identisch damit. Collections müssen nicht explizit angelegt werden, sie werden bei der ersten Verwendung automatisch erzeugt. In unserer Datenbank test gibt es zunächst noch keine Collections:

> show collections
>

2.4.2 Dokumente

Dokumente werden innerhalb der Mongo Shell im JSON4-Format repräsentiert. Das JSON-Format ist ein leichtgewichtiges, textbasiertes Format, in dem man ein Objekt gut lesbar darstellen kann, z. B.:

> doc = { hello: "MongoDB" }

Im obigen Beispiel ist doc ein Dokument mit einem Feld namens hello, das den String-Wert "MongoDB" hat.

Wir werden in Kapitel 3 noch genauer auf Collections und Dokumente eingehen.

2.4.3 CRUD-Operationen

Ich werde nun in der Collection dokumente einige Dokumente speichern, manipulieren und suchen. Mit

> db.dokumente.insert( doc )
> db.dokumente.insert( {a: 1, b: "zwei" } )
> db.dokumente.insert( {a: 2, b: "drei" } )

ist das Speichern bereits erledigt. Das JavaScript-Objekt db repräsentiert in der Mongo Shell die aktuell selektierte Datenbank. Collections werden automatisch zu Attributen dieses Datenbankobjekts und sind daher über den Ausdruck db.name oder db["name"] zugreifbar. Mit dem ersten schreibenden Zugriff auf die Collection dokumente wurde diese angelegt, wie die Auflistung aller Collections nun zeigt:

> show collections
dokumente
system.indexes

Mit db.dokumente.help() erhalten Sie Hilfe zu den Befehlen der Collection.

Neben unserer Collection dokumente ist auch eine weitere Collection system. indexes entstanden, die Informationen über Indizes enthält (mehr dazu in Kap. 6). Wir können nun die zuvor eingefügten Dokumente z. B. zählen oder auch suchen:

> db.dokumente.count()
3
> db.dokumente.find()
{ "_id" : ObjectId("50ba1112b9b2400412cbe6bd"),
    "hello" : "MongoDB" }
{ "_id" : ObjectId("50ba1112b9b2400412cbe6be"),
    "a" : 1, "b" : "zwei" }
{ "_id" : ObjectId("50ba112eb9b2400412cbe6bf"),
    "a" : 2, "b" : "drei" }

Dabei fällt auf, dass beim Schreiben ein Feld _id erzeugt wurde, mit dem das Dokument eindeutig identifiziert werden kann. Das Feld _id wird automatisch ergänzt, wenn Sie es nicht selbst angeben.

Da man oft nicht an allen Dokumenten innerhalb einer Collection interessiert ist, kann man der Methode find(...) Suchkriterien und Feldgruppen in Form von Dokumenten mitgeben, um die Treffermenge einzuschränken, z. B.:

> db.dokumente.find( {a: 2}, {_id: 0} )
{ "a" : 2, "b" : "drei" }

In diesem Beispiel schränken wir mit dem ersten Parameter {a: 2} die Menge der gefundenen Dokumente auf solche ein, bei denen das Feld a den Wert 2 besitzt. Mit dem optionalen zweiten Parameter schränken wir die Menge der zurückgelieferten Felder innerhalb eines Dokuments ein, indem wir für Felder, die wir ignorieren möchten, eine 0 angeben. (In SQL würden Sie an dieser Stelle eine konkrete Spaltenliste anstatt von * beim SELECT angeben.)

Neben dem einfachen Feldvergleich auf Identität gibt es noch viele weitere sog. Query-Operatoren, die ich ausführlich in Kapitel 6 erklären werde.

Im Gegensatz zu relationalen Datenbanken kann ein einzelnes Feld eines Dokuments aber auch Arrays oder eingebettete Unterobjekte enthalten:

> db.autoren.insert( {
    titel: "MongoDB: Ein praktischer Einstieg",
    autoren:[
        {name: "N.N."},
        {name: "Tobias Trelle"}
    ]
} )

Eine anschließende Suche mit Formatierung macht die Struktur deutlicher:

> db.autoren.find().pretty()
{
"_id" : ObjectId("50ba1bafb9b2400412cbe6c0"),
"titel" : "Praxisbuch MongoDB",
"autoren" : [
    {
    "name" : "N.N"
    },
    {
    "name" : "Tobias Trelle"
    }
]
}

Wenn wir nun ein bestimmtes Objekt verändern wollen, können wir die Methode update(...) verwenden:

> db.dokumente.update( {a: 2}, {b: "vier"} )

Intuitiv würde man nun vielleicht vermuten, dass im Dokument mit a = 2 der Wert für b auf "vier" gesetzt wurde. Dies ist aber nicht der Fall, wie eine anschließende Suche zeigt (mit leerem Suchkriterien-Dokument {} werden alle Dokumente gefunden):

> db.dokumente.find({}, {_id: 0})
{ "a" : 1, "b" : "zwei" }
{ "b" : "vier" }

Die Semantik der update(...) -Methode ist so, dass der zweite Parameter (hier {b: "vier"}) das bestehende Dokument vollständig ersetzt und nicht nur die darin vorkommenden Fehler manipuliert!

Partielle Updates und noch einiges mehr sind aber dennoch möglich und werden in Kapitel 7 ausführlich behandelt.

Einzelne Dokumente werden mit remove(...) gelöscht:

> db.dokumente.remove( {a: 1} )
> db.dokumente.find({}, {_id: 0})
{ "b" : "vier" }

Um alle Dokumente einer Collection zu löschen, ruft man remove() ohne Parameter auf. Dies kann bei großen Datenmengen sehr lange dauern, da jedes Dokument einzeln gelöscht wird, was z. B. auch eine Aktualisierung von Indizes auslösen kann. Schneller ist man hier mit:

> db.dokumente.drop()
true
> show collections
system.indexes

Mit drop() wird die Collection vollständig gelöscht, inklusive aller bestehenden Indizes.

2.5 Daten importieren

Die bisherigen Beispiele mögen Ihnen zu Recht trivial vorkommen. Im weiteren Verlauf des Buchs werden wir auf eine größere und komplexere Datenmenge zurückgreifen. Es handelt sich um einen Auszug aus öffentlich zugänglichen Tweets der Twitter-Plattform. Diese Daten können Sie von

https://github.com/ttrelle/mongodb-buch/blob/master/data/tweets.zip?raw=true

herunterladen und ins Verzeichnis MONGO_HOME entpacken. Der Inhalt des Archivs ist eine Datei im BSON-Format, die gut 50.000 Dokumente beinhaltet, die wir gleich in eine Collection einspielen werden.

Beenden Sie dazu nun die Mongo Shell mit dem Befehl exit. Anschließend rufen Sie im Verzeichnis MONGO_HOME\bin den folgenden Befehl auf, um die Daten in eine Datenbank namens twitter in eine Collection namens tweets zu importieren:

$ mongorestore -d twitter../tweets.bson
connected to: 127.0.0.1
2014-02-27T08:30:07.181+0100 tweets.bson
2014-02-27T08:30:07.185+0100    going into namespace [twitter.tweets]
2014-02-27T08:30:07.187+0100 tweets.metadata.json not found. Skipping.
2014-02-27T08:30:10.002+0100          Progress: 76560817/85711256     89%
(bytes)
53641 objects found

Die Ausführungszeit des Importvorgangs kann in Abhängigkeit von Ihrem System variieren. Sobald die Daten importiert sind, rufen wir wieder die Mongo Shell auf und wechseln in die Twitter-Datenbank, um uns die Anzahl der Tweets anzuzeigen:

$ mongo
MongoDB shell version: 2.x
connecting to: test
> use twitter
switched to db twitter
> show collections
system.indexes
tweets
> db.tweets.count()
53641

Wenn wir nun mittels

> db.tweets.find()

nach allen importierten Tweets suchen, gibt die Mongo Shell einen Wust von Dokumenten aus. Die Anzahl der angezeigten Dokumente wird per Default auf 20 beschränkt. Diese Anzahl wird bestimmt durch:

> DBQuery.shellBatchSize
20

Um die jeweils nächste Tranche der Ergebnismenge anzuzeigen, geben Sie bitte den Befehl it ein. Um Dokumente lesbarer anzuzeigen, verwenden Sie diesen Befehl:

> db.tweets.find().pretty()

Probieren Sie einfach mal ein paar Suchen nach verschiedenen Kriterien aus. Die Hilfe zur find()- Methode unterstützt Sie dabei.

> db.tweets.find().help()

Alle weiteren Details zu Queries und auch zur Indexierung finden Sie in Kapitel 6.

2.6 Schemafreiheit

Eines der Alleinstellungsmerkmale von MongoDB ist die sogenannte Schemafreiheit, auf die ich in Kapitel 8 noch genauer eingehen werde. Zum Einstieg will ich Ihnen anhand eines einfachen Beispiels die Möglichkeiten aufzeigen, die Sie ohne ein starres Schema haben.

Sie können z. B. einen Produktkatalog mit den unterschiedlichsten Produkttypen innerhalb einer Collection realisieren:

> use shop
switched to db shop
> db.produkte.insert({
  typ: "dvd",
  titel: "Lost Highway",
  regie: "David Lynch"
})
> db.produkte.insert({
  typ: "cd",
  titel: "Highway to Hell",
  band: "AC/DC"
})

Die Suche nach gemeinsamen Feldern der unterschiedlichen Produkte ist ganz einfach:

> db.produkte.find({titel: /Highway/})
{     "_id" : ObjectId("530eefa913109e3002c125de"),
      "typ" : "dvd",
      "titel" : "Lost Highway",
      "regie" : "David Lynch" }
{     "_id" : ObjectId("530eefe313109e3002c125df"),
      "typ" : "cd",
      "titel" : "Highway to Hell",
      "band" : "AC/DC" }

Eine Einschränkung auf bestimmte Produktarten ist dabei möglich:

> db.produkte.find({titel: /Highway/, typ: "cd"})
...

Das gilt ebenso für die Suche nach Feldern, die es nur für bestimmte Produkte gibt:

> db.produkte.find({regie: "David Lynch"})
...

Das Beispiel ist zugegebenermaßen trivial, deutet aber die Mächtigkeit an, die die Schemafreiheit beim Umgang mit semistrukturierten Daten bietet. Hier kristallisiert sich einer der Hauptvorteile von MongoDB heraus, der insbesondere auch den Big-Data-Aspekt Variety adressiert.

2.7 Zusammenfasssung

In diesem Kapitel haben Sie gesehen, wie einfach der Einstieg in MongoDB ist. Nach den ersten Schritten haben Sie bereits Daten importiert und die Vorteile der Schemafreiheit kennengelernt. Im nächsten Kapitel werde ich Ihnen die technologischen Grundlagen für all das näher erklären.

3 Grundlegende Konzepte

Nachdem Sie im letzten Kapitel die ersten praktischen Erfahrungen mit MongoDB und der Mongo Shell gesammelt haben, werden wir nun näher auf die dahinter liegenden Konzepte und Begriffe eingehen und die technischen Grundlagen beleuchten, auf denen MongoDB basiert.

Kapitel 6