Kurs
Als beliebte NoSQL-Datenbank bietet MongoDB eine flexible und skalierbare Möglichkeit, deine Daten zu verwalten. Dieser Leitfaden ist dein Startpunkt, um die intuitive Query API zu meistern. Sie ermöglicht dir die Interaktion mit deinen Daten über BSON (Binary JSON), das für Effizienz und Datentypen optimiert ist.
Im Verlauf des Artikels behandeln wir die grundlegenden Create-, Read-, Update-, Delete- (CRUD) Operationen, tauchen in präzises Abfragen mit Filtern und Projektionen ein, erkunden die Stärke von Aggregation-Pipelines zur Datenumwandlung und sprechen über Indexe, um die Performance zu steigern. Am Ende verfügst du über ein solides Fundament, um Daten in deinen MongoDB-Collections effizient abzurufen und zu bearbeiten.
Grundlagen: CRUD-Operationen
Das Rückgrat jeder Datenbankinteraktion ist CRUD: Create, Read, Update und Delete. Schauen wir uns an, wie du jede davon in MongoDB ausführst.
Daten erstellen (insert)
Um neue Dokumente zu einer Collection hinzuzufügen, nutzt du die insert-Methoden. Dokumente in MongoDB sind JSON-ähnliche Objekte.
insertOne()
Diese Methode fügt ein einzelnes Dokument zu einer Collection hinzu.
// A sample document to insert
const newProduct = {
name: "Wireless Mouse",
brand: "Logitech",
price: 29.99,
inStock: true
};
// Insert the new document into the 'products' collection
db.products.insertOne(newProduct);
insertMany()
Diese Methode fügt mehrere Dokumente auf einmal hinzu und ist deutlich effizienter, als sie einzeln einzufügen.
// An array of documents to insert
const newProducts = [
{ name: "Mechanical Keyboard", brand: "Corsair", price: 129.99, inStock: false },
{ name: "Gaming Headset", brand: "Razer", price: 99.99, inStock: true },
{ name: "Webcam", brand: "LogiTech", price: 79.99, inStock: true }
];
// Insert the array of documents into the 'products' collection
db.products.insertMany(newProducts);
Daten lesen (find)
Die Methode find() ist dein primäres Werkzeug, um Dokumente aus einer Collection abzurufen. Beim Aufruf von find() erhältst du nicht sofort alle Dokumente zurück. Stattdessen gibt MongoDB einen Cursor zurück. Das ist ein effizienter Weg, um potenziell große Ergebnismengen zu verarbeiten, ohne alles auf einmal in den Speicher zu laden.
Der einfachste find()-Aufruf benötigt keine Argumente und liefert einen Cursor für jedes Dokument in der Collection.
// Find and return a cursor to all documents in the 'products' collection
db.products.find();
So sieht dieses Cursor-Objekt in der mongosh (der MongoDB-Shell) aus und so kannst du damit arbeiten:
// Find all products and assign the returned cursor to a variable
const productCursor = db.products.find();
// The variable 'productCursor' now holds the cursor object, not the documents themselves.
// To get the documents, you need to iterate over the cursor.
// You can convert the cursor to an array to see all the documents
const allProducts = productCursor.toArray();
console.log(allProducts);
// Or, you can manually iterate through the documents
while (productCursor.hasNext()) {
const product = productCursor.next();
console.log(product);
}
Der Cursor selbst ist ein Objekt mit Methoden wie toArray(), hasNext() und next(), mit denen du die Dokumente im Resultset abrufen und damit arbeiten kannst.
Daten aktualisieren (update)
Um bestehende Dokumente zu ändern, verwendest du die update-Methoden. Diese nehmen zwei Hauptargumente: einen Filter, um die zu ändernden Dokumente auszuwählen, und einen Update-Operator, der die Änderungen definiert. Ein häufiger Operator ist $set, der den Wert eines Felds setzt.
updateOne()
Diese Methode aktualisiert das erste Dokument, das dem Filter entspricht.
// Update the 'Wireless Mouse' document to set its price to 39.99
db.products.updateOne(
{ name: "Wireless Mouse" }, // Filter to find the document
{ $set: { price: 39.99 } } // Update operator
);
updateMany()
Diese Methode aktualisiert alle Dokumente, die dem angegebenen Filter entsprechen.
// Update all 'LogiTech' brand products to be in stock
db.products.updateMany(
{ brand: "LogiTech" }, // Filter to find the documents
{ $set: { inStock: true } } // Update operator
);
Daten löschen (delete)
Um Dokumente zu entfernen, nutzt du die delete-Methoden. Auch hier definierst du per Filter, welche Dokumente gelöscht werden.
deleteOne()
Diese Methode entfernt das erste Dokument, das dem Filter entspricht.
// Delete the 'Webcam' document
db.products.deleteOne({ name: "Webcam" });
deleteMany()
Diese Methode entfernt alle Dokumente, die dem Filter entsprechen. Um alle Dokumente in einer Collection zu löschen, kannst du einen leeren Filter {} übergeben.
// Delete all documents that are not in stock
db.products.deleteMany({ inStock: false });
Präziser Abruf: Query-Filter
Query-Filter sind das Herzstück der Leistungsfähigkeit von MongoDB. Sie sind das erste Argument in den Methoden find() und update und erlauben dir, punktgenau auszuwählen, mit welchen Dokumenten du arbeiten willst.
Vergleichsoperatoren
Diese Operatoren vergleichen den Feldwert mit einem angegebenen Wert.
$eq (gleich)
Findet Dokumente, bei denen ein Feld einem Wert entspricht.
// Find all products that are made by 'Razer'
db.products.find({ brand: { $eq: "Razer" } });
// This can be simplified to:
// db.products.find({ brand: "Razer" });
$gt und $gte (größer als, größer oder gleich)
Findet Dokumente, deren Feldwert größer als ($gt) oder größer/gleich ($gte) einem bestimmten Wert ist.
// Find all products with a price greater than 100
db.products.find({ price: { $gt: 100 } });
$lt und $lte (kleiner als, kleiner oder gleich)
Findet Dokumente, deren Feldwert kleiner als ($lt) oder kleiner/gleich ($lte) einem bestimmten Wert ist.
// Find all products with a price less than or equal to 50
db.products.find({ price: { $lte: 50 } });
$ne (ungleich)
$ne findet Dokumente, bei denen ein Feld nicht einem angegebenen Wert entspricht.
// Find all products that are NOT made by 'LogiTech'
db.products.find({ brand: { $ne: "LogiTech" } });
$in und $nin (in Array, nicht in Array)
Findet Dokumente, deren Feldwert in ($in) oder nicht in ($nin) einem angegebenen Werte-Array enthalten ist.
// Find all products from 'Razer' or 'Corsair'
db.products.find({ brand: { $in: ["Razer", "Corsair"] } });
Logische Operatoren
Logische Operatoren kombinieren mehrere Bedingungen zu komplexen Abfragen.
$and
$and verknüpft Bedingungen logisch mit UND. Alle Bedingungen müssen zutreffen.
// Find all products with a price greater than 50 AND are in stock
db.products.find({ $and: [{ price: { $gt: 50 } }, { inStock: true }] });
// This can be simplified by just listing the conditions:
// db.products.find({ price: { $gt: 50 }, inStock: true });
$or
Verknüpft Bedingungen logisch mit ODER. Mindestens eine Bedingung muss zutreffen.
// Find all products with a brand of 'Corsair' OR a price less than 40
db.products.find({ $or: [{ brand: "Corsair" }, { price: { $lt: 40 } }] });
Element- und Auswertungsoperatoren
Diese Operatoren bieten zusätzliche Flexibilität beim Filtern.
$exists
$exists findet Dokumente, die ein bestimmtes Feld enthalten.
// Find all documents that have an 'inStock' field
db.products.find({ inStock: { $exists: true } });
$regex
Ermöglicht reguläre Ausdrücke für Musterabgleiche in String-Feldern.
// Find all product names that start with 'Wireless'
db.products.find({ name: { $regex: /^Wireless/ } });
Ausgaben formen: Projektion
Bei einer find()-Operation kannst du festlegen, nur einen Teil der Felder eines Dokuments zu erhalten. Das nennt sich Projektion und ist das zweite Argument von find(). So reduzierst du Datenübertragung und -verarbeitung.
Felder einblenden
Du kannst angeben, welche Felder zurückgegeben werden sollen, indem du ihren Wert auf 1 setzt.
// Find all products and return only the 'name' and 'price' fields
db.products.find({}, { name: 1, price: 1 });
Felder ausblenden
Umgekehrt kannst du Felder ausblenden, indem du ihren Wert auf 0 setzt.
// Find all products and hide the 'inStock' field
db.products.find({}, { inStock: 0 });
Das Feld _id wird standardmäßig immer zurückgegeben, sofern du es nicht explizit ausschließt.
Das Feld _id
Um das Feld _id auszublenden, musst du es explizit auf 0 setzen.
// Find all products, returning only 'name' and 'price', and hiding '_id'
db.products.find({}, { _id: 0, name: 1, price: 1 });
Fortgeschrittene Datenumwandlung: Aggregation-Pipelines
Aggregation ist ein mächtiges Framework zur Datenverarbeitung in MongoDB. Eine Aggregation-Pipeline besteht aus einer Abfolge von Stufen, die Dokumente verarbeiten und die Ergebnisse jeweils an die nächste Stufe weiterreichen.
$match
Die Stufe $match filtert Dokumente anhand eines Query-Filters – genau wie bei find(). Oft ist dies die erste Stufe, um die zu verarbeitende Dokumentenmenge zu reduzieren.
// Find all products with a brand of 'LogiTech'
db.products.aggregate([
{ $match: { brand: "LogiTech" } }
]);
$group
Die Stufe $group gruppiert Dokumente anhand eines angegebenen _id-Ausdrucks und kann Akkumulator-Operationen wie Summe oder Durchschnitt über ein Feld ausführen.
// Group products by brand and calculate the total number of products for each brand
db.products.aggregate([
{ $group: { _id: "$brand", totalProducts: { $sum: 1 } } }
]);
$project
Die Stufe $project formt jedes Dokument im Stream um – ähnlich der Projektion in find(). Du kannst neue Felder hinzufügen, bestehende entfernen und Daten manipulieren.
// Project a new field 'nameAndPrice' for each document
db.products.aggregate([
{ $project: { name: 1, price: 1, nameAndPrice: { $concat: ["$name", " (", "$price", ")"] } } }
]);
$sort
Die Stufe $sort sortiert Dokumente nach einem angegebenen Feld. Der Wert 1 steht für aufsteigend, -1 für absteigend.
// Sort all products by price in descending order
db.products.aggregate([
{ $sort: { price: -1 } }
]);
$limit und $skip
Diese Stufen nutzt du für Pagination. $skip überspringt eine angegebene Anzahl an Dokumenten vom Anfang der Pipeline, und $limit begrenzt die Anzahl der an die nächste Stufe weitergereichten Dokumente.
// Skip the first 10 products and then return the next 5
db.products.aggregate([
{ $skip: 10 },
{ $limit: 5 }
]);
Ein einfaches Pipeline-Beispiel
Hier ein vollständiges Beispiel, das zeigt, wie diese Stufen zusammenarbeiten.
// Find the average price of all products that are currently in stock,
// grouped by brand.
db.products.aggregate([
{ $match: { inStock: true } }, // Filter for products in stock
{ $group: { _id: "$brand", averagePrice: { $avg: "$price" } } } // Group and calculate average price
]);
Leistung steigern: Indexe
Indexe sind spezielle Datenstrukturen, die einen kleinen, leicht durchsuchbaren Teil der Daten einer Collection speichern. Sie verbessern die Abfrageperformance erheblich, indem MongoDB Dokumente schnell findet und abruft, ohne die gesamte Collection scannen zu müssen.
createIndex()
Du erstellst einen Index auf einem Feld, nach dem du häufig filterst oder sortierst.
// Create a single-field index on the 'brand' field
db.products.createIndex({ brand: 1 });
Die 1 steht für aufsteigende Sortierung im Index. Du kannst -1 für absteigend verwenden, was bei entsprechend sortierenden Abfragen vorteilhaft sein kann.
Ein Index auf einem Feld wie brand beschleunigt Abfragen, die nach brand filtern (z. B. db.products.find({ brand: "Razer" })) – insbesondere, wenn deine Collection wächst.
Worauf solltest du indexieren?
Typischerweise legst du Indexe auf Feldern an, die du häufig in Abfragen nutzt – etwa in einem find()-Filter oder in der $match-Stufe einer Aggregation.
- Kardinalität: Felder mit vielen eindeutigen Werten (hohe Kardinalität), wie z. B. die E-Mail-Adresse eines Nutzers, sind hervorragende Kandidaten für Indexe.
- Selektivität der Abfrage: Ein Feld, das für eine gegebene Abfrage nur einen kleinen Teil der Dokumente zurückliefert, ist ebenfalls sehr gut geeignet.
- Sortierung: Wenn du Ergebnisse häufig nach einem bestimmten Feld sortierst, macht ein Index auf diesem Feld die Sortierung deutlich schneller.
Auswirkungen auf Abfragen
Indexe haben einen erheblichen Einfluss auf die Performance. Eine Abfrage mit Index ist oft um Größenordnungen schneller als dieselbe Abfrage ohne Index.
// Conceptual illustration of performance difference
// Without an index on 'brand':
// MongoDB performs a full collection scan, checking every document.
// This is slow, especially with millions of documents.
db.products.find({ brand: "Razer" });
// With an index on 'brand':
// MongoDB uses the index to quickly locate and return only the matching documents.
// This is very fast.
db.products.find({ brand: "Razer" });
Um Abfragen weiter zu optimieren, kannst du die Methode db.collection.explain() verwenden, um die Abfrageperformance zu analysieren und zu sehen, wie Indexe genutzt werden.
Fazit: Dein Weg zur MongoDB-Expertise
Du hast gerade einen Crashkurs in der MongoDB Query API abgeschlossen! Du weißt nun, wie du zentrale CRUD-Operationen ausführst, mit leistungsfähigen Filtern gezielt Daten abrufst, deine Ausgabe per Projektion formst und deine Daten mit Aggregation-Pipelines transformierst. Außerdem hast du ein Grundverständnis davon, wie Indexe die Performance verbessern.
Dieser Leitfaden bietet ein solides Fundament, und am besten verinnerlichst du die Konzepte durch Praxis. Probier verschiedene Abfragen aus und wirf einen Blick in die vollständige Dokumentation, um weitere fortgeschrittene Operatoren und Features zu entdecken. Viel Spaß beim Coden!
MongoDB Query API FAQs
What is the main difference between find() and aggregate()?
Die Methode find() dient dem einfachen Abruf von Dokumenten mit optionalen Filtern und Projektionen. Die Methode aggregate() hingegen ist ein mächtiges Framework für mehrstufige Datenverarbeitung, mit dem du Dokumente komplex transformieren, gruppieren, sortieren und umformen kannst. Während find() Dokumente so liest, wie sie sind, hilft dir aggregate(), neue Erkenntnisse aus deinen Daten abzuleiten.
Why does MongoDB return a cursor from a find() operation instead of the actual documents?
Ein Cursor ist eine effiziente Möglichkeit, potenziell große Ergebnismengen zu handhaben. Indem MongoDB einen Cursor zurückgibt, werden nicht alle Dokumente auf einmal in den Speicher geladen. Das ist entscheidend für Leistung und Skalierbarkeit, besonders bei Millionen von Dokumenten. Der Cursor erlaubt es dir, die Ergebnisse nach Bedarf zu durchlaufen und Dokumente in Batches abzurufen.
When should I use updateOne() vs. updateMany()?
Nutze updateOne(), wenn du nur das erste Dokument ändern willst, das deinem Filter entspricht. Das ist ideal, wenn du erwartest, dass nur ein Dokument passt – etwa bei der Abfrage über einen eindeutigen Identifikator. Verwende updateMany(), wenn alle Dokumente aktualisiert werden sollen, die die Filterkriterien erfüllen.
How do indexes improve query performance?
Indexe sind spezielle Datenstrukturen, die einen kleinen, organisierten Teil der Daten einer Collection speichern. Sie beschleunigen Abfragen deutlich, weil MongoDB Dokumente schnell lokalisieren kann, ohne die gesamte Collection zu scannen. Statt jedes Dokument einzeln zu prüfen, nutzt die Datenbank den Index, um direkt zu den passenden Dokumenten zu springen – das macht die Operation um Größenordnungen schneller.
Can I mix projection with aggregation?
Ja, Projektion ist ein zentraler Bestandteil der Aggregation-Pipeline. Die Stufe $project dient dazu, Dokumente umzuformen, neue Felder hinzuzufügen oder bestehende zu entfernen. Häufig wird sie nach Stufen wie $match oder $group eingesetzt, um die Ausgabe der Pipeline zu formatieren und dir eine fein abgestimmte Kontrolle über die finale Datenstruktur zu geben.
Karen ist eine Dateningenieurin mit einer Leidenschaft für den Aufbau skalierbarer Datenplattformen. Sie hat Erfahrung mit der Automatisierung von Infrastrukturen mit Terraform und freut sich darauf, ihre Erfahrungen in Blogbeiträgen und Tutorials zu teilen. Karen ist eine Community-Builderin und setzt sich leidenschaftlich für die Förderung von Verbindungen zwischen Datenexperten ein.
