Das Datenmodell von MongoDB unterscheidet sich fundamental von relationalen Datenbanken. Statt Tabellen mit festen Spalten und Zeilen arbeitet MongoDB mit flexiblen Dokumenten, die in Collections organisiert sind. Dieses Modell folgt einer klaren Hierarchie: Datenbanken enthalten Collections, Collections enthalten Dokumente. Diese drei Ebenen bilden das Fundament, auf dem alle weiteren Konzepte aufbauen.
Ein Dokument ist die kleinste Einheit in MongoDB – vergleichbar mit einer Zeile in SQL, aber weitaus mächtiger. Technisch ist ein Dokument ein BSON-Objekt (Binary JSON), das aus Schlüssel-Wert-Paaren besteht. Die Syntax ähnelt JSON und ist für Entwickler sofort vertraut. Ein einfaches Benutzerdokument könnte etwa Name, Alter und E-Mail-Adresse enthalten.
Die eigentliche Stärke von Dokumenten liegt in ihrer Fähigkeit, komplexe Strukturen abzubilden. Anders als eine SQL-Zeile, die nur atomare Werte enthalten kann, unterstützt ein MongoDB-Dokument verschachtelte Objekte und Arrays. Ein Dokument kann andere Dokumente enthalten – sogenannte eingebettete Dokumente oder Embedded Documents. Diese Verschachtelung ermöglicht es, zusammengehörige Daten als kohärente Einheit zu speichern.
Betrachten wir ein realistisches Beispiel – ein Benutzerprofil für eine Social-Media-Plattform:
{
"_id": ObjectId("507f1f77bcf86cd799439011"),
"username": "anna.mueller",
"email": "anna@example.com",
"profile": {
"firstName": "Anna",
"lastName": "Müller",
"birthDate": ISODate("1994-03-15T00:00:00Z"),
"bio": "Fotografin aus Berlin",
"avatar": "https://cdn.example.com/avatars/anna.jpg"
},
"address": {
"street": "Hauptstraße 45",
"city": "Berlin",
"zip": "10115",
"country": "DE"
},
"interests": ["Fotografie", "Reisen", "Kochen"],
"settings": {
"newsletter": true,
"privacy": "friends",
"theme": "dark"
},
"createdAt": ISODate("2023-01-10T14:23:00Z"),
"lastLogin": ISODate("2024-01-05T09:15:00Z")
}Dieses Dokument zeigt mehrere wichtige Charakteristiken. Das
_id-Feld ist der Primärschlüssel – MongoDB generiert
automatisch eine ObjectId, wenn keine explizit angegeben wird. Diese
12-Byte-Sequenz ist global eindeutig und enthält einen Timestamp, was
praktisch für Sortierung und Debugging ist.
Die Felder profile und address sind
eingebettete Dokumente – vollständige Objekte innerhalb des
Hauptdokuments. Statt wie in SQL separate Tabellen für Profile und
Adressen zu haben, die über Fremdschlüssel verknüpft werden, speichert
MongoDB alles zusammen. Dies hat einen entscheidenden Vorteil: Eine
einzige Read-Operation liefert alle Daten. Keine Joins, keine mehrfachen
Abfragen – ein Dokument enthält alles.
Das Array interests demonstriert, wie MongoDB Listen von
Werten handhabt. In SQL würde dies typischerweise eine separate Tabelle
user_interests mit Fremdschlüsseln erfordern. In MongoDB
ist es einfach ein Array im Dokument. Dies vereinfacht nicht nur die
Datenmodellierung, sondern auch Queries: “Finde alle Benutzer, die sich
für Fotografie interessieren” ist eine simple Array-Abfrage.
Die Datentypen in diesem Dokument zeigen die Vielfalt von BSON. Strings, Numbers und Booleans stammen aus JSON. ISODate ist ein BSON-spezifischer Typ für präzise Zeitstempel. ObjectId ist ebenfalls BSON-spezifisch. Diese zusätzlichen Typen machen BSON mächtiger als reines JSON und ermöglichen effiziente Operationen wie Datumsvergleiche oder numerische Berechnungen.
Ein fundamentales Prinzip von MongoDB ist die Schemafreiheit auf
Dokumentebene. Zwei Dokumente in derselben Collection können völlig
unterschiedliche Felder haben. Ein Benutzer könnte ein
address-Feld haben, ein anderer nicht. Dies ist in SQL
unmöglich – jede Zeile muss die gleichen Spalten haben, auch wenn viele
NULL sind. In MongoDB ist ein fehlendes Feld einfach nicht vorhanden,
was Speicher spart und die Modellierung vereinfacht.
Diese Flexibilität ist mächtig, aber nicht ohne Risiken. Ohne
Disziplin können inkonsistente Datenstrukturen entstehen. Ein Teil der
Anwendung schreibt firstName, ein anderer
first_name. Solche Inkonsistenzen führen zu Bugs. MongoDB
bietet deshalb Schema-Validierung an – optionale Regeln, die
Dokumentstrukturen erzwingen können. Dies ist ein bewusster Trade-off:
Flexibilität wo sinnvoll, Struktur wo nötig.
Eine Collection ist eine Gruppe von Dokumenten, konzeptionell vergleichbar mit einer Tabelle in SQL. Der entscheidende Unterschied: Collections erzwingen kein Schema. Dokumente mit völlig unterschiedlichen Strukturen können friedlich in derselben Collection koexistieren. Dies ist bewusst so designed – nicht als Versehen, sondern als Feature.
Der Name einer Collection sollte ihren Zweck widerspiegeln.
Konventionen wie Plural (users, orders,
products) und Kleinschreibung sind weit verbreitet, aber
nicht erzwungen. MongoDB erlaubt Unicode in Collection-Namen, was auch
deutsche Umlaute ermöglicht – wovon allerdings abzuraten ist, da es
Tool-Kompatibilität beeinträchtigen kann.
Betrachten wir eine realistische Collection products für
einen E-Commerce-Shop:
// Elektronik-Produkt
{
"_id": ObjectId("..."),
"sku": "LAPTOP-001",
"name": "ThinkPad X1 Carbon",
"category": "electronics",
"price": 1499.99,
"specs": {
"cpu": "Intel i7-1165G7",
"ram": "16GB",
"storage": "512GB SSD",
"display": "14\" FHD"
},
"warranty": 36,
"inStock": true,
"quantity": 15
}
// Kleidungsstück
{
"_id": ObjectId("..."),
"sku": "SHIRT-042",
"name": "Bio-Baumwolle T-Shirt",
"category": "clothing",
"price": 29.99,
"sizes": ["S", "M", "L", "XL"],
"colors": ["weiß", "schwarz", "navy"],
"material": "100% Bio-Baumwolle",
"care": "30°C Maschinenwäsche",
"inStock": true,
"inventory": {
"S": 20,
"M": 35,
"L": 28,
"XL": 12
}
}
// Lebensmittel
{
"_id": ObjectId("..."),
"sku": "FOOD-089",
"name": "Bio Haferflocken",
"category": "food",
"price": 3.99,
"weight": "500g",
"nutrition": {
"calories": 379,
"protein": 13.5,
"carbs": 67.7,
"fat": 7.0
},
"allergens": ["Gluten"],
"organic": true,
"expiryDate": ISODate("2024-12-31T00:00:00Z"),
"inStock": true,
"quantity": 150
}Diese drei Dokumente leben in derselben Collection, haben aber völlig
unterschiedliche Felder. Das Laptop hat specs und
warranty, das T-Shirt hat sizes und
material, die Haferflocken haben nutrition und
allergens. Gemeinsam ist ihnen nur das Notwendigste:
sku, name, category,
price, inStock.
In SQL würde dies typischerweise eine von zwei Lösungen erfordern. Entweder separate Tabellen pro Produkttyp (mit der Herausforderung, über alle Typen hinweg zu suchen), oder eine Tabelle mit Dutzenden von Spalten, wo jedes Produkt nur einen Bruchteil nutzt. MongoDB macht beides unnötig – heterogene Produkte koexistieren natürlich.
Die Schemafreiheit von Collections bedeutet nicht Beliebigkeit. In
der Praxis haben Dokumente einer Collection meist ähnliche Strukturen,
weil sie vom gleichen Code geschrieben und gelesen werden. Ein gewisser
gemeinsamer Nenner – wie die Felder name,
price, inStock oben – entsteht organisch aus
den Anforderungen der Anwendung.
Collections können explizit erstellt werden, aber MongoDB erzeugt sie
auch automatisch beim ersten Insert. Ein
db.newcollection.insertOne({...}) auf einer nicht
existierenden Collection erzeugt diese implizit. Für spezielle
Anforderungen – wie Schema-Validierung oder Capped Collections mit
fester Größe – ist explizite Erstellung sinnvoll.
Eine Datenbank in MongoDB ist ein Container für Collections. Eine MongoDB-Instanz kann mehrere Datenbanken hosten, typischerweise eine pro Anwendung oder Microservice. Diese Trennung ist nicht nur organisatorisch, sondern auch operativ: Jede Datenbank hat eigene Dateien auf dem Dateisystem, eigene Locks und kann unabhängig gesichert werden.
Die Namensgebung folgt ähnlichen Konventionen wie Collections:
aussagekräftig, Kleinschreibung, keine Sonderzeichen. Namen wie
ecommerce, analytics oder
user_profiles sind typisch. Systemdatenbanken wie
admin, config und local sind
reserviert und haben spezielle Bedeutungen in MongoDBs interner
Verwaltung.
Eine typische MongoDB-Instanz für ein Unternehmen könnte mehrere Datenbanken hosten:
Die physische Trennung auf Datenbankebene hat praktische
Konsequenzen. Backups können pro Datenbank erfolgen, was bei großen
Systemen Zeit spart. Zugriffsrechte werden typischerweise auf
Datenbankebene vergeben – ein Benutzer hat Leserechte auf
ecommerce, aber keine auf analytics. Diese
Granularität unterstützt das Prinzip der minimalen Rechte.
Queries sind datenbankspezifisch. Eine Verbindung zur MongoDB-Shell
oder ein Application-Connection geschieht immer im Kontext einer
Datenbank. use ecommerce wechselt in der Shell zur
Datenbank ecommerce, danach beziehen sich alle Befehle auf
deren Collections. Ein db.products.find() sucht in
ecommerce.products, nicht in
analytics.products, selbst wenn beide existieren.
Cross-Database-Operationen sind limitiert. Ein $lookup
(MongoDBs Äquivalent zu SQL Joins) kann Collections aus derselben
Datenbank verknüpfen. Über Datenbanken hinweg ist dies nicht möglich.
Diese Limitation ist bewusst gewählt – sie fördert klare Architekturen,
wo zusammengehörige Daten auch zusammen liegen.
Die Freiheiten des dokumentenorientierten Modells erfordern bewusste Entscheidungen bei der Datenmodellierung. Die zentrale Frage ist oft: Daten einbetten oder referenzieren? Diese Entscheidung prägt Performance, Konsistenz und Wartbarkeit.
Einbettung (Embedding) bedeutet, zusammengehörige Daten als verschachtelte Dokumente zu speichern. Das Benutzer-Beispiel oben bettet Adresse und Profil ein. Vorteil: Eine Query liefert alles, keine Joins nötig. Nachteil: Redundanz, wenn dieselben Daten an mehreren Stellen benötigt werden, und Größenlimitierung – ein Dokument darf maximal 16 MB groß sein.
Referenzierung bedeutet, Dokumente über IDs zu verknüpfen, ähnlich
Fremdschlüsseln in SQL. Ein Order-Dokument könnte etwa nur die
customer_id speichern, nicht das gesamte Customer-Dokument.
Vorteil: Keine Redundanz, flexiblere Updates. Nachteil: Mehrere Queries
oder $lookup-Operationen nötig, was Performance kostet.
Die Entscheidung hängt von Zugriffsmustern ab. Werden Daten fast immer gemeinsam gelesen? Einbetten. Werden sie unabhängig voneinander aktualisiert oder haben ein stark differierendes Wachstum? Referenzieren. Ein klassisches Beispiel: Blog-Posts und Kommentare. Bei wenigen Kommentaren pro Post kann Einbettung sinnvoll sein. Bei Tausenden wird Referenzierung notwendig, um das 16-MB-Limit nicht zu überschreiten.
Die folgende Tabelle fasst die Entscheidungskriterien zusammen:
| Kriterium | Einbettung bevorzugen | Referenzierung bevorzugen |
|---|---|---|
| Lesemuster | Daten werden fast immer zusammen gelesen | Daten werden oft unabhängig gelesen |
| Schreibmuster | Kind-Daten ändern sich selten | Kind-Daten ändern sich häufig |
| Datenmenge | Vorhersehbar klein (< 1 MB pro Dokument) | Potenziell groß oder unbegrenzt wachsend |
| Redundanz | Akzeptabel oder nicht vorhanden | Problematisch |
| Konsistenz | Atomare Updates nötig | Separate Updates sind OK |
Das dokumentenorientierte Modell von MongoDB ist nicht komplexer als SQL – es ist anders. Die Denkweise verschiebt sich von normalisierten Tabellen hin zu natürlichen Objektstrukturen. Entwickler, die von SQL kommen, neigen anfangs dazu, zu stark zu normalisieren. Mit Erfahrung kommt die Erkenntnis, dass MongoDB Denormalisierung nicht nur toleriert, sondern oft bevorzugt. Ein gut modelliertes MongoDB-Schema folgt den Anforderungen der Anwendung, nicht abstrakten Normalisierungsregeln.