Dokumentdatenbank

MongoDB

MongoDB ist eine Dokumentdatenbank: Flexible BSON-Dokumente leben in Collections, werden mit einer JavaScript-ähnlichen Sprache abgefragt und skalieren über Replica Sets und Sharding.

intermediate15 min readUpdated 16. Sept. 2026
mongosh
js
// mongosh
use shop

db.orders.insertOne({
  customerId: ObjectId("64f1c2a9e13b4a7d8c9e0011"),
  status: "paid",
  items: [
    { sku: "KB-01", name: "Keyboard", qty: 1, price: 8900 },
    { sku: "MS-02", name: "Mouse", qty: 2, price: 2900 },
  ],
  total: 14700,
  createdAt: new Date(),
})

db.orders
  .find({ status: "paid", total: { $gte: 10000 } })
  .sort({ createdAt: -1 })
  .limit(10)
Veröffentlicht
2009
Datenmodell
Dokument / BSON
Abfragesprache
MQL
Geschrieben in
C++
Storage Engine
WiredTiger
Lizenz
SSPL
Version
8.x

Warum es wichtig ist

Warum Teams zu MongoDB greifen

Dokumente entsprechen Objekten

Ein Datensatz ist ein BSON-Dokument, das das Objekt widerspiegelt, das deine Anwendung bereits verwendet. Dadurch benötigen Lesezugriffe selten Joins oder ein Row-to-Object-Mapping.

Eine lesbare Abfragesprache

Filter sind JSON-ähnliche Dokumente mit Operatoren wie $gt und $in, was Abfragen komponierbar und einfach programmatisch erstellbar macht.

Skalieren, wenn nötig

Replica Sets bieten von Tag eins an hohe Verfügbarkeit, und Sharding verteilt eine Collection über mehrere Nodes, wenn ein einzelner Primary nicht mehr ausreicht.

Das Gesamtbild

Die drei Kernideen hinter MongoDB

Ein Dokument speichert ein ganzes Objekt, eine Collection gruppiert Dokumente, und ein Index oder eine Pipeline verwandelt sie in Antworten.

Dokumente

Speichern

Daten leben in BSON-Dokumenten mit typisierten Feldern, verschachtelten Objekten und Arrays. Das Schema wird durch deinen Code erzwungen, nicht durch den Server.

Collections & Indexe

Organisieren

Zugehörige Dokumente befinden sich in einer Collection. Indexe auf den Feldern, nach denen gefiltert und sortiert wird, verwandeln Full Scans in gezielte Lookups.

Driver & Mongoose

Zugreifen

Der offizielle Node-Driver stellt dieselben Befehle bereit, die du in mongosh ausführst, während Mongoose Schemas, Validierung und Modelle hinzufügt.

HTML5 auf einen Blick

Der MongoDB-Werkzeugkasten

Collections

db.orders ist eine Collection von Dokumenten, die beim ersten Insert erstellt wird.

find()

Übergib ein Filter-Dokument und erhalte einen Cursor mit den passenden Dokumenten.

Aggregation

Eine Pipeline aus $match, $group und $lookup Stages formt die Ergebnisse.

Indexe

Single, Compound, Unique, TTL und Text-Indexe teilen sich eine einzige API.

Transaktionen

Multi-Dokument ACID-Transaktionen, wenn ein einzelner Schreibvorgang nicht ausreicht.

Replica Sets

Ein Primary und Secondaries replizieren Schreibvorgänge und wählen einen neuen Primary.

Datenmodell

Wie ein Dokument aufgebaut ist

Eine Bestellung, ihre Positionen und ihr Status – alles in einem einzigen Dokument.

Ein Bestell-DokumentMongoDB Dokument
  • _idObjectIdPrimärschlüssel, generiert durch den Driver
  • customerIdObjectIdReferenziert ein Dokument in users
  • statusstringpending, paid oder shipped
  • itemsarray<object>Eingebettete Positionen: sku, name, qty, price
  • totalnumberAbgeleitete Gesamtsumme in Cent
  • createdAtDateIndexiert für Abfragen nach aktuellen Bestellungen

Ein Dokument in der orders Collection, mit eingebetteten Positionen und einem indexierten Status.

Der vollständige Leitfaden

MongoDB: Alles was Sie wissen müssen

Was ist MongoDB?

MongoDB ist eine Dokumentdatenbank. Anstatt Zeilen in Tabellen speichert sie Dokumente — JSON-ähnliche Objekte, die als BSON kodiert sind — innerhalb von Collections. Ein Dokument kann verschachtelte Objekte und Arrays enthalten, sodass ein einziger Datensatz ein ganzes Aggregat beschreiben kann: beispielsweise eine Bestellung mit all ihren Positionen oder einen Benutzer mit seinen Adressen.

MongoDB erschien im Jahr 2009, als das relationale Modell für Anwendungen, die schnell wuchsen und ihre Struktur änderten, zu schwerfällig wirkte. Das Versprechen war simpel: Speichere das Objekt, das dein Code bereits verwendet, und skaliere horizontal, ohne eine mühsame Migration durchführen zu müssen. Dieses Versprechen machte MongoDB zur Standard-NoSQL-Datenbank für eine ganze Generation von Node.js- und JavaScript-Teams.

Der Kompromiss ist jedoch real. MongoDB verzichtet standardmäßig auf Joins und verlagert die Schema-Validierung in deine Anwendung. Wenn deine Daten dokumentenförmig sind, ist das ein hervorragender Deal. Wenn sie jedoch tief relational sind, ist eine relationale Datenbank oft das bessere Werkzeug.

Dokumente, Collections und BSON

Ein Dokument ist eine geordnete Menge von Feld-Wert-Paaren. Eine Collection ist eine Gruppe von Dokumenten, die normalerweise eine ähnliche Struktur aufweisen, obwohl dies nicht zwingend erforderlich ist. Collections werden in dem Moment erstellt, in dem Sie zum ersten Mal Daten in sie einfügen.

db.users.insertOne({
  email: "[email protected]",
  name: "Ada",
  address: { city: "London", country: "GB" },
  tags: ["admin", "beta"],
});

Werte haben BSON-Typen, nicht nur JSON-Typen. BSON ist eine binäre Kodierung, die ObjectId, Date, Decimal128, BinData und mehr hinzufügt, sodass Sie echte Datumsangaben und präzise Dezimalzahlen anstelle von Strings speichern können. Die Reihenfolge der Felder bleibt erhalten und Feldnamen sind case-sensitive.

Eine nützliche Gewohnheit ist es, jedem Dokument in einer Collection eine konsistente Struktur zu geben, auch wenn der Server Variationen zulässt. Dadurch erhalten Sie vorhersagbare Queries und Indizes, während die Flexibilität erhalten bleibt, falls Sie ein Feld zunächst nur in einem einzelnen Dokument hinzufügen müssen.

_id und ObjectId

Jedes Dokument benötigt eine eindeutige _id. Wenn Sie keine angeben, generiert der Driver eine ObjectId – einen 12-Byte-Wert, der aus einem Zeitstempel, einem zufälligen prozessspezifischen Wert und einem inkrementierenden Zähler besteht. Da der Zeitstempel an erster Stelle steht, lassen sich ObjectId-Werte in etwa nach ihrer Erstellungszeit sortieren, was für die Pagination sehr praktisch ist.

const { ObjectId } = require("mongodb");

const id = new ObjectId("64f1c2a9e13b4a7d8c9e0011");
id.getTimestamp(); // 2023-09-01T...

Das _id-Feld wird automatisch indiziert und ist immer eindeutig. Sie können einen eigenen Wert angeben – einen natürlichen Schlüssel, einen UUID-String oder einen zusammengesetzten Schlüssel –, wenn dies die Abfragen effizienter macht oder wenn Sie idempotente Inserts benötigen.

CRUD in der Praxis

Create, Read, Update und Delete lassen sich auf eine kleine Gruppe von Methoden abbilden, die in mongosh und im Node driver identisch funktionieren.

// Create
db.users.insertOne({ email: "[email protected]", plan: "pro" });
db.users.insertMany([
  { email: "[email protected]", plan: "free" },
  { email: "[email protected]", plan: "team" },
]);

// Read
db.users.findOne({ email: "[email protected]" });
db.users.find({ plan: "pro" }).toArray();

// Update
db.users.updateOne(
  { email: "[email protected]" },
  { $set: { plan: "team" } },
);

// Delete
db.users.deleteOne({ email: "[email protected]" });

updateOne und updateMany nehmen einen Filter und ein Update-Dokument entgegen. Das Update-Dokument verwendet Operatoren: $set ersetzt oder fügt Felder hinzu, $unset entfernt sie, $inc addiert zu einer Zahl, $push fügt einem Array Elemente hinzu, $addToSet fügt nur hinzu, wenn das Element nicht vorhanden ist, und $pull entfernt passende Array-Elemente.

db.users.updateOne(
  { email: "[email protected]" },
  {
    $set: { lastSeenAt: new Date() },
    $inc: { logins: 1 },
    $addToSet: { tags: "beta" },
  },
);

Es gibt zudem replaceOne, welches das gesamte Dokument außer _id ersetzt. Bevorzuge Feld-Operatoren, damit sich konkurrierende Schreiber nicht gegenseitig die Änderungen überschreiben.

Abfragen mit Operatoren

Ein Filter ist selbst ein Dokument. Standardmäßig wird auf Gleichheit geprüft; Operatoren beginnen mit $.

db.orders.find({ status: "paid" });                     // equality
db.orders.find({ total: { $gt: 5000, $lte: 20000 } });  // range
db.orders.find({ status: { $in: ["paid", "shipped"] } });
db.users.find({ email: { $regex: /@example\.com$/i } });
db.orders.find({ "items.sku": "KB-01" });               // nested field
db.orders.find({
  items: { $elemMatch: { qty: { $gte: 2 }, price: { $lt: 3000 } } },
});

$elemMatch ist wichtig, wenn mehrere Bedingungen auf dasselbe Element eines Arrays zutreffen müssen. Ohne diesen Operator könnte { "items.qty": { $gte: 2 }, "items.price": { $lt: 3000 } } verschiedene Elemente matchen.

Kombinieren Sie Filter mit $and, $or und $not:

db.orders.find({
  $or: [
    { status: "paid" },
    { status: "pending", total: { $lt: 1000 } },
  ],
});

Die Abfragesprache ist komponierbar, da sie aus Daten und nicht aus einem String besteht. Deshalb fühlt sich das Erstellen von Filtern im Anwendungscode natürlich an – Sie setzen ein Objekt zusammen und übergeben es an find.

Projektion, Sortierung und Pagination

Eine Projektion legt fest, welche Felder zurückgegeben werden sollen. Felder werden mit 1 eingeschlossen oder mit 0 ausgeschlossen, wobei diese beiden Stile niemals gemischt werden dürfen, außer bei _id.

db.users.find(
  { plan: "pro" },
  { email: 1, name: 1, _id: 0 },
);

Sortierung und Pagination werden mit .sort(), .skip() und .limit() realisiert. Bei großen Offsets wird skip langsamer, da der Server die übersprungenen Dokumente dennoch durchläuft. Bevorzugen Sie Keyset-Pagination, bei der Sie nach dem letzten gesehenen Wert filtern.

db.orders
  .find({ customerId, createdAt: { $lt: lastSeen } })
  .sort({ createdAt: -1 })
  .limit(20);

Indizes auf den Sortierfeldern machen sowohl den Filter als auch die Sortierung effizient – und genau hier setzt der nächste Abschnitt an.

Indexe: der Unterschied zwischen schnell und unbrauchbar

Ohne einen Index liest MongoDB jedes Dokument in der Collection – ein sogenannter Collection Scan. Mit einem Index springt die Datenbank direkt zum passenden Bereich. Fast jedes Performance-Problem in MongoDB ist auf einen fehlenden oder falsch angeordneten Index zurückzuführen.

db.users.createIndex({ email: 1 }, { unique: true });
db.orders.createIndex({ customerId: 1, createdAt: -1 });
db.sessions.createIndex({ expiresAt: 1 }, { expireAfterSeconds: 0 });
db.products.createIndex({ name: "text", description: "text" });
  • Single-field Indexe beschleunigen Equality- und Range-Queries auf einem einzelnen Feld.
  • Compound Indexe folgen der ESR-Regel: zuerst Equality-Felder, dann Sortierung, dann Range. { customerId: 1, createdAt: -1 } bedient sowohl den Filter als auch die Sortierung.
  • Unique Indexe verhindern Duplikate und machen Upserts sicher.
  • TTL Indexe löschen Dokumente nach einem bestimmten Datum, was ideal für Sessions und Einmal-Token ist.
  • Text Indexe unterstützen $text Suche mit Stemming und Scoring.

Nutzen Sie explain(), um zu sehen, was der Planner getan hat. Achten Sie auf IXSCAN anstelle von COLLSCAN und prüfen Sie, ob die Anzahl der untersuchten Dokumente nahe an der Anzahl der zurückgegebenen Dokumente liegt.

db.orders.find({ customerId, status: "paid" }).explain("executionStats");

Die Aggregation Pipeline

Wenn eine einfache Abfrage nicht ausreicht, führt das Aggregation Framework eine Pipeline von Stages aus. Jede Stage transformiert einen Dokumentenstrom und gibt diesen an die nächste Stage weiter. Die gängigsten Stages sind $match, $group, $sort, $project, $lookup, $unwind und $limit.

Hier ist ein praxisnahes Beispiel: die fünf umsatzstärksten Produkte bei bezahlten Bestellungen.

db.orders.aggregate([
  { $match: { status: "paid" } },
  { $unwind: "$items" },
  {
    $group: {
      _id: "$items.sku",
      units: { $sum: "$items.qty" },
      revenue: {
        $sum: { $multiply: ["$items.qty", "$items.price"] },
      },
    },
  },
  { $sort: { revenue: -1 } },
  { $limit: 5 },
  {
    $project: {
      _id: 0,
      sku: "$_id",
      units: 1,
      revenue: 1,
    },
  },
]);

Lies die Pipeline von oben nach unten. $match filtert bereits früh, damit nachfolgende Stages weniger Arbeit verrichten müssen. $unwind wandelt jedes Array-Element in ein eigenes Dokument um. $group summiert die Einheiten und den Umsatz pro SKU. $sort und $limit behalten die Top fünf. $project benennt _id in sku um und verwirft den Rest.

$lookup führt einen Left Outer Join mit einer anderen Collection durch – so kombinierst du referenzierte Daten:

db.orders.aggregate([
  { $match: { status: "paid" } },
  {
    $lookup: {
      from: "users",
      localField: "customerId",
      foreignField: "_id",
      as: "customer",
    },
  },
  { $unwind: "$customer" },
  { $project: { total: 1, "customer.email": 1 } },
]);

Setze $match immer an den Anfang, damit ein Index genutzt werden kann, und platziere $limit so früh wie möglich, sofern es die Logik erlaubt. Aggregation ist mächtig, aber eine Pipeline, die in jeder Stage jedes einzelne Dokument scannt, führt unweigerlich zu langsamen Abfragen.

Embedding vs. Referencing

Dies ist die zentrale Entscheidung beim Datenmodelling. Überlegen Sie hierzu, wie die Daten gelesen werden.

Embedden Sie Daten, wenn die Child-Daten zusammen mit dem Parent gelesen und geschrieben werden und ihre Größe begrenzt ist. Die Positionen einer Bestellung sind der klassische Fall: Ein einziger Lesezugriff liefert alles zurück, und es ist kein Join erforderlich.

{
  _id: ObjectId("..."),
  customerId: ObjectId("..."),
  items: [
    { sku: "KB-01", qty: 1, price: 8900 },
    { sku: "MS-02", qty: 2, price: 2900 },
  ],
  total: 14700,
}

Referenzieren Sie Daten, wenn diese groß sind, geteilt werden oder in ihrem eigenen Zyklus aktualisiert werden. Benutzer, Produkte und Kategorien werden durch _id referenziert, und $lookup oder eine zweite Abfrage führt den Join durch.

{
  _id: ObjectId("..."),
  customerId: ObjectId("64f1c2a9e13b4a7d8c9e0011"),
  items: [{ productId: ObjectId("..."), qty: 1, price: 8900 }],
}

Die Faustregel lautet: Daten, auf die gemeinsam zugegriffen wird, sollten gemeinsam gespeichert werden. Duplizieren Sie gegebenenfalls geringfügig Daten, wenn dies den häufigsten Lesezugriff zu einem einzigen Lookup macht, aber bedenken Sie, dass Kopien an jeder Stelle aktualisiert werden müssen, an der sie existieren. Und embedden Sie niemals ein Array, das unbegrenzt wächst – Dokumente sind auf 16 MB begrenzt.

Transaktionen

Schreibvorgänge in einem einzelnen Dokument sind atomar. Wenn Sie mehrere Dokumente oder Collections als eine Einheit ändern müssen, verwenden Sie eine Multi-Document-Transaktion. Sessions sind hierfür der Mechanismus.

const session = client.startSession();

try {
  await session.withTransaction(async () => {
    await accounts.updateOne(
      { _id: from },
      { $inc: { balance: -100 } },
      { session },
    );
    await accounts.updateOne(
      { _id: to },
      { $inc: { balance: 100 } },
      { session },
    );
  });
} finally {
  await session.endSession();
}

Transaktionen erfordern ein Replica Set oder einen sharded Cluster und bringen einen gewissen Overhead mit sich: Locks, ein längeres Zeitfenster und Retries bei Konflikten. Der optimale Einsatz von Transaktionen ist selten. Wenn Sie feststellen, dass Sie jeden Schreibvorgang in eine Transaktion einschließen, sollte Ihr Datenmodell wahrscheinlich mehr Embedding nutzen.

Replica Sets und Sharding

Ein Replica Set ist eine Gruppe von Nodes, die dieselben Daten halten. Einer davon ist der Primary und übernimmt alle Schreibvorgänge; die anderen replizieren das oplog des Primarys und können Lesezugriffe bedienen. Wenn der Primary ausfällt, wählt das Set automatisch einen neuen aus. Dies ist das Standard-Deployment für die Produktion und ermöglicht zudem Change Streams und Transaktionen.

Sharding partitioniert eine Collection über viele Replica Sets hinweg mithilfe eines Shard Keys. Jeder Shard besitzt einen bestimmten Bereich von Key-Werten. Ein guter Shard Key weist eine hohe Kardinalität auf, verteilt Schreibvorgänge gleichmäßig und taucht in den meisten Queries auf, sodass der Router einen einzelnen Shard ansteuern kann. Ein schlechter Key erzeugt Hotspots oder zwingt jede Query dazu, sich auf alle Shards zu verteilen (Fan-out).

Wählen Sie den Shard Key aus, bevor Sie Daten haben, da eine spätere Änderung die Migration der gesamten Collection bedeutet. Für die meisten Anwendungen ist es ratsam, mit einem Replica Set zu starten und erst dann auf Sharding umzustellen, wenn ein einzelner Primary nicht mehr mithalten kann.

Mongoose in Node

Der offizielle mongodb Driver reicht für einfache Abfragen völlig aus, aber die meisten Node-Teams setzen auf Mongoose aufgrund der Schemas, Validierungen und Modelle. Ein Schema beschreibt die Struktur eines Dokuments, und ein Modell ist die daraus resultierende, abfragbare Klasse.

import mongoose from "mongoose";

const orderSchema = new mongoose.Schema({
  customerId: {
    type: mongoose.Schema.Types.ObjectId,
    ref: "User",
    required: true,
  },
  status: {
    type: String,
    enum: ["pending", "paid", "shipped"],
    default: "pending",
  },
  items: [
    {
      sku: String,
      qty: { type: Number, min: 1 },
      price: { type: Number, min: 0 },
    },
  ],
  total: Number,
  createdAt: { type: Date, default: Date.now, index: true },
});

export const Order = mongoose.model("Order", orderSchema);

const paid = await Order.find({ status: "paid" })
  .sort({ createdAt: -1 })
  .limit(20)
  .lean();

Mongoose validiert beim Speichern, führt Typumwandlungen (Casting) durch und bietet populate() für Referenzen. Zwei Gewohnheiten halten die Performance hoch: Deklarieren Sie die Indexe, die Ihre Abfragen benötigen, und nutzen Sie .lean(), wenn Sie Daten nur lesen möchten – so wird das Erstellen vollständiger Mongoose-Dokumente übersprungen.

Bulk-Writes und Upserts

Ein Befehl pro Dokument verschwendet Roundtrips. Wenn Sie viele Änderungen anwenden müssen, sendet bulkWrite einen Batch in einem einzigen Aufruf und berichtet genau, was passiert ist.

await db.users.bulkWrite([
  {
    updateOne: {
      filter: { email: "[email protected]" },
      update: { $set: { plan: "team" } },
      upsert: true,
    },
  },
  {
    insertOne: {
      document: { email: "[email protected]", plan: "pro" },
    },
  },
  {
    deleteOne: { filter: { email: "[email protected]" } },
  },
]);

Die upsert-Option ist das andere Arbeitstier. Sie aktualisiert ein passendes Dokument oder fügt eines ein, falls keines existiert, was idempotente Importe und Counter vereinfacht.

db.stats.updateOne(
  { day: "2026-09-16" },
  { $inc: { visits: 1 } },
  { upsert: true },
);

Bulk-Writes sind standardmäßig keine Transaktionen. Übergeben Sie { ordered: false }, um nach einem Fehler fortzufahren und jeden Fehlschlag zu sammeln, oder bleiben Sie beim standardmäßigen ordered mode, wenn jeder Schreibvorgang vom vorherigen abhängt. Überprüfen Sie in jedem Fall das Result-Objekt: Es zählt die gematchten, modifizierten, eingefügten und gelöschten Dokumente; ein Upsert, das keine Übereinstimmung fand, ist kein Fehler.

Change Streams

Ein Replica Set zeichnet jeden Schreibvorgang in einem oplog auf. Change Streams stellen dieses Log als wiederaufnehmbaren Feed bereit, sodass eine Anwendung auf Inserts, Updates und Deletes reagieren kann, ohne Polling nutzen zu müssen.

const changeStream = db.orders.watch([
  { $match: { "fullDocument.status": "paid" } },
]);

for await (const change of changeStream) {
  console.log(change.operationType, change.fullDocument._id);
}

Der Feed ist wiederaufnehmbar: Speichern Sie den _id des letzten verarbeiteten Events als Resume Token und übergeben Sie diesen nach einem Neustart mit resumeAfter, damit kein Event verloren geht. Da Change Streams auf dem oplog basieren, setzen sie ein Replica Set voraus und melden nur Änderungen, die noch nicht aus dem Log gelöscht wurden.

Zwei Regeln sorgen für die Zuverlässigkeit: Machen Sie den Consumer idempotent, da ein Event nach einem Resume erneut zugestellt werden kann. Und halten Sie die Verarbeitung schnell oder lagern Sie die Arbeit in eine Queue aus, da ein langsamer Consumer dazu führt, dass das oplog an seiner Position vorbeiläuft.

Best Practices

  • Modellierung für den Lesezugriff: Bette Daten ein, die gemeinsam gelesen werden; referenziere Daten, die geteilt oder unbegrenzt wachsen.
  • Indexiere die Felder, nach denen gefiltert und sortiert wird, und befolge die ESR-Regel für zusammengesetzte Indexe.
  • Projiziere immer nur die Felder, die der Client tatsächlich benötigt; gib niemals Secrets zurück.
  • Setze $match an den Anfang einer Aggregation Pipeline, damit ein Index genutzt werden kann.
  • Begrenze das Wachstum von Arrays und achte auf das 16 MB Dokumenten-Limit.
  • Validiere Schreibvorgänge in der Applikation oder mit einem JSON Schema Validator der Collection.
  • Nutze explain(), bevor du davon ausgehst, dass eine Query performant ist, und teste diese mit produktionsnahen Datenmengen.
  • Bevorzuge Keyset-Pagination gegenüber großen skip Offsets.

Häufige Fehler

  • MongoDB als komplett schemalos zu betrachten und Dokumente in inkompatible Formen driften zu lassen.
  • Abfragen ohne Index auszuführen und sich zu wundern, warum die Latenz mit der Größe der Collection steigt.
  • Compound-Indizes in der falschen Reihenfolge zu erstellen, sodass die Sortierung diese nicht nutzen kann.
  • Arrays einzubetten, die unendlich wachsen, bis die Dokumente das Größenlimit erreichen.
  • $lookup bei jeder Anfrage zu verwenden, anstatt Daten einzubetten, die gemeinsam gelesen werden.
  • Zu Multi-Dokument-Transaktionen zu greifen, wenn ein Update eines einzelnen Dokuments ausreichen würde.
  • Ganze Dokumente zurückzugeben und dabei Passwort-Hashes oder Tokens preiszugeben.
  • Einen Shard-Key mit geringer Kardinalität zu wählen und so einen Write-Hotspot zu erzeugen.

Wie geht es weiter?

MongoDB vermittelt Dokumentmodellierung, Index-Design und Aggregation – Fähigkeiten, die auf jeden Datenspeicher übertragbar sind. Wenn Ihre Daten stark relational sind und Joins sowie Constraints auf Datenbankebene benötigen, lesen Sie den PostgreSQL-Guide. Für Lesezugriffe im Mikrosekundenbereich, TTL-gesteuertes Ablaufdatum und Counter kombinieren Sie MongoDB mit Redis. Wenn Sie MongoDB mit einem Node-Service verbinden möchten, schauen Sie sich die Node.js basics noch einmal an und vergleichen Sie anschließend das Query-Modell mit SQL.

In der Praxis

Vier Befehle, die den Großteil der Arbeit abdecken

Die gleichen Strukturen erscheinen in mongosh und im Node-Driver: insert, update, aggregate und index.

mongosh
db.users.insertMany([
  { email: "[email protected]", name: "Ada", plan: "pro" },
  { email: "[email protected]", name: "Linus", plan: "free" },
]);

db.users.find(
  { plan: "pro" },
  { email: 1, name: 1, _id: 0 },
);

Nur das Nötigste projizieren

Eine Projektion reduziert die Bytes, die über das Netzwerk übertragen werden, und hält sensible Felder aus den Antworten fern.

Bevorzugt
db.users.find(
  { plan: "pro" },
  { email: 1, name: 1, _id: 0 },
);
Vermeiden
db.users.find({ plan: "pro" });
// every field crosses the wire,
// including passwordHash and tokens

Arrays begrenzt halten

Bette Daten ein, die zusammen gelesen werden, aber lass ein einzelnes Dokument niemals ohne Limit wachsen. Dokumente haben eine Obergrenze von 16 MB.

Bevorzugt
// Line items are read with the order.
db.orders.insertOne({
  customerId,
  items: [{ sku: "KB-01", qty: 1, price: 8900 }],
});
Vermeiden
// This array grows forever.
db.users.updateOne(
  { _id },
  { $push: { events: event } },
);

Abwägungen

Ist MongoDB der richtige Speicher dafür?

MongoDB ist exzellent für dokumentenförmige Lesezugriffe und horizontale Skalierung. Die Kosten entstehen, wenn Daten tief relational sind oder starke Garantien über Dokumentgrenzen hinweg benötigen.

Strengths

  • Das Objekt ist der Datensatz

    Das Speichern eines Dokuments, das bereits der Form deiner Anwendung entspricht, entfernt die Mapping-Schicht, und viele Lesezugriffe werden zu einem einzigen Lookup.

  • Schema-Flexibilität

    Dokumente in einer Collection können unterschiedliche Felder haben, was sich ideal für evolvierende Produkte und heterogene Daten eignet.

  • Integrierte horizontale Skalierung

    Replica Sets und Sharding sind First-Class-Citizens, sodass dasselbe Datenmodell von einem einzelnen Node zu einem Cluster wachsen kann.

Trade-offs

  • Beziehungen werden komplexer

    Ohne Standard-Joins bedeutet die Modellierung von Many-to-Many-Daten Duplikation oder $lookup; die Konsistenz der Kopien zu wahren, liegt in deiner Verantwortung.

  • Schema-on-write ist immer noch ein Schema

    Der Server wird ein fehlerhaftes Dokument nicht stoppen. Die Validierung muss in deinem Code oder in einem JSON Schema Validator erfolgen.

  • Transaktionen kosten mehr

    Multi-Dokument-Transaktionen funktionieren, sind aber langsamer und komplexer als ein Single-Dokument-Update. Designe deine Daten so, dass du sie selten benötigst.

Häufig gestellte Fragen

Häufig gestellte Fragen

Keep learning

Related topics from the roadmap.

$ Lernen Sie jetzt

Bereit, MongoDB zu lernen?

Unser interaktives Tutorial führt Sie Schritt für Schritt durch MongoDB — mit Quizzen und echtem Code, den Sie im Browser ausführen können.