Sort, Skip, Limit und Projektionen kombinieren
Sie kombinieren Filter, Projektion, Sortierung und Paginierung zu einer vollständigen Abfragekette für einen realistischen Listenendpunkt.
Sort, Skip, Limit und Projektionen kombinieren ist eine kostenlose MongoDB Academy-Lektion auf CoddyKit. Dies ist Lektion 4 von 4. Du kannst die komplette Lektion unten kostenlos lesen – dann übst du sie direkt im Browser mit einem integrierten Code-Editor und einem KI-Tutor rund um die Uhr. Sie ist Teil des MongoDB Academy-Lernpfads, und dein Fortschritt wird über Web und CoddyKit-App synchronisiert. Der MongoDB Academy-Kurs umfasst insgesamt 4 Lektionen.
Die vollständige Abfragekette
Eine MongoDB-Listenabfrage in Produktionsqualität kombiniert vier Komponenten: einen Filter zur Auswahl passender Dokumente, eine Projektion zur Auswahl der zurückzugebenden Felder, eine Sortierung zur Anordnung der Ergebnisse und eine Paginierung (skip/limit oder Keyset-Paginierung), um jeweils eine Seite zurückzugeben. Für das Schreiben korrekter und leistungsfähiger Abfragen ist es entscheidend zu verstehen, wie diese Komponenten zusammenwirken und in welcher Reihenfolge MongoDB sie ausführt.
Die interne Ausführungsreihenfolge von MongoDB
Unabhängig davon, in welcher Reihenfolge Sie Methoden im Treiber verketten, führt MongoDB Abfragekomponenten immer in dieser festen Reihenfolge aus: 1) Filter → 2) Sortierung → 3) Skip → 4) Limit. Die Projektion wird angewendet, während Dokumente aus der Storage Engine gelesen werden. Diese Reihenfolge ist wichtig: skip arbeitet mit der sortierten Ergebnismenge, und limit begrenzt die endgültige Ausgabe nach dem Überspringen. Sie können diese Ausführungsreihenfolge nicht ändern.
// These two are identical — order of chaining doesn't matter
db.products.find({}).sort({ price: -1 }).skip(20).limit(10);
db.products.find({}).limit(10).skip(20).sort({ price: -1 });
// MongoDB executes: filter -> sort -> skip -> limitEinen List-API-Endpunkt erstellen
Fügen wir alle Bestandteile in einem realistischen Listen-Endpunkt zusammen. Das folgende Beispiel ruft Seite 2 aktiver Produkte aus der Kategorie „electronics“ ab, sortiert nach absteigender Bewertung, und gibt nur die für eine Produktkarten-Oberfläche benötigten Felder zurück. Jeder Bestandteil der Kette erfüllt einen bestimmten Zweck.
const filter = { category: 'electronics', isActive: true };
const projection = { _id: 1, name: 1, price: 1, thumbnailUrl: 1, rating: 1 };
const PAGE = 2;
const PAGE_SIZE = 20;
const products = await db.collection('products')
.find(filter) // 1. filter
.project(projection) // projection
.sort({ rating: -1, _id: -1 }) // 2. sort
.skip((PAGE - 1) * PAGE_SIZE) // 3. skip
.limit(PAGE_SIZE) // 4. limit
.toArray();Der unterstützende Index
Damit die vollständige Abfragekette effizient ist, benötigen Sie einen Index, der Filter und Sortierung abdeckt. Der Filter verwendet category und isActive (Gleichheit), die Sortierung verwendet rating und _id. Der ideale zusammengesetzte Index platziert zuerst die Gleichheitsfelder und danach die Sortierfelder: { category: 1, isActive: 1, rating: -1, _id: -1 }.
// Index supporting the list API query
db.products.createIndex({ category: 1, isActive: 1, rating: -1, _id: -1 });
// Verify: explain should show IXSCAN and no SORT stage
db.products.find({ category: 'electronics', isActive: true })
.sort({ rating: -1, _id: -1 })
.skip(20)
.limit(20)
.explain('executionStats');Die vollständige Mongoose-Abfragekette
Die Fluent API von Mongoose macht dieselbe Abfragekette lesbar und typsicher. Verketten Sie .find(), .select(), .sort(), .skip() und .limit(), und rufen Sie anschließend .lean() für ein einfaches POJO-Ergebnis auf (deutlich schneller als vollständige Mongoose-Dokumente, wenn Sie keine Lifecycle-Hooks oder Virtuals benötigen).
const products = await Product
.find({ category: 'electronics', isActive: true })
.select({ name: 1, price: 1, thumbnailUrl: 1, rating: 1, _id: 1 })
.sort({ rating: -1, _id: -1 })
.skip((PAGE - 1) * PAGE_SIZE)
.limit(PAGE_SIZE)
.lean(); // returns plain objects, not Mongoose Documents
console.log('Products on page:', products.length);Paginierungsmetadaten zurückgeben
Die Antwort einer gut konzipierten Listen-API enthält neben dem Datenarray Paginierungsmetadaten: die aktuelle Seite, die Seitengröße, die Gesamtzahl der Dokumente, die Gesamtzahl der Seiten sowie die Information, ob eine nächste oder vorherige Seite vorhanden ist. So können Clients Paginierungssteuerelemente darstellen, ohne eine separate Count-Abfrage auszuführen. Geben Sie Metadaten und Daten immer gemeinsam in einem Antwortobjekt zurück.
const [total, items] = await Promise.all([
Product.countDocuments({ category: 'electronics', isActive: true }),
Product.find({ category: 'electronics', isActive: true })
.select({ name: 1, price: 1, thumbnailUrl: 1, rating: 1 })
.sort({ rating: -1 })
.skip((PAGE - 1) * PAGE_SIZE)
.limit(PAGE_SIZE)
.lean()
]);
res.json({
data: items,
page: PAGE,
pageSize: PAGE_SIZE,
total: total,
totalPages: Math.ceil(total / PAGE_SIZE),
hasNext: PAGE * PAGE_SIZE < total,
hasPrev: PAGE > 1
});Standardwerte anwenden und Eingaben validieren
Validieren und bereinigen Sie die Query-Parameter page, limit und sort immer, bevor Sie sie in einer MongoDB-Abfrage verwenden. Ungeprüfte Werte können Fehler durch skip(-5), enorme limit(999999)-Aufrufe mit übermäßigem Speicherverbrauch oder Sortier-Injection verursachen, wenn Sie vom Benutzer bereitgestellte Sortierschlüssel direkt weitergeben. Erlaubte Sortierfelder sollten auf einer Whitelist stehen; außerdem sollten Sie sinnvolle Mindest- und Höchstwerte für page und limit erzwingen.
const ALLOWED_SORT_FIELDS = new Set(['rating', 'price', 'createdAt']);
function parseListParams(query) {
const page = Math.max(1, parseInt(query.page) || 1);
const limit = Math.min(100, Math.max(1, parseInt(query.limit) || 20));
const sortField = ALLOWED_SORT_FIELDS.has(query.sort) ? query.sort : 'createdAt';
const sortDir = query.order === 'asc' ? 1 : -1;
return { page, limit, sort: { [sortField]: sortDir, _id: sortDir } };
}Zwischen Offset- und Keyset-Paginierung wechseln
Sie können beide Paginierungsmodi über denselben Endpunkt anbieten, indem Sie prüfen, ob ein cursor-Parameter (Keyset) oder ein page-Parameter (Offset) vorhanden ist. Wenn cursor angegeben ist, wenden Sie den Bereichsfilter an und lassen skip() weg. Wenn nur page angegeben ist, verwenden Sie skip(). So können Sie Clients schrittweise von der Offset- auf die Keyset-Paginierung umstellen, ohne die Abwärtskompatibilität zu beeinträchtigen.
async function listItems(req, res) {
const limit = 20;
let query = Product.find({ isActive: true }).sort({ createdAt: -1, _id: -1 }).limit(limit);
if (req.query.cursor) {
const { createdAt, _id } = decodeCursor(req.query.cursor);
query = query.where('$or').equals([
{ createdAt: { $lt: new Date(createdAt) } },
{ createdAt: new Date(createdAt), _id: { $lt: _id } }
]);
} else if (req.query.page) {
const page = Math.max(1, parseInt(req.query.page) || 1);
query = query.skip((page - 1) * limit);
}
const items = await query.lean();
res.json({ items, nextCursor: items.length === limit ? encodeCursor(items.at(-1)) : null });
}Die Abfragekette testen
Testen Sie Ihre vollständige Abfragekette sowohl mit Unit-Tests (Mocking des Treibers) als auch mit Integrationstests (echtes MongoDB über ein In-Memory-mongod oder Testcontainers). Befüllen Sie die Test-Collection mit genügend Dokumenten, um die Korrektheit der Paginierungsgrenzen zu überprüfen: Seite 1 und Seite 2 müssen zusammen genau 2×pageSize unterschiedliche Dokumente ohne Duplikate oder Lücken zurückgeben.
Paginierte Ergebnisse zwischenspeichern
Erwägen Sie bei leseintensiven paginierten APIs, Antworten auf HTTP-Ebene (Redis oder ein CDN) zwischenzuspeichern. Verwenden Sie dabei die vollständige Query-Zeichenfolge einschließlich page, sort und Filtern als Schlüssel. Cache-TTLs von 10–60 Sekunden reduzieren die Datenbanklast bei häufigen Abfragen erheblich. Beachten Sie, dass zwischengespeicherte Antworten leicht veraltete Daten enthalten können – für die meisten Anwendungsfälle akzeptabel, jedoch nicht für Finanz- oder Echtzeit-Dashboards.
Die vollständige Kette mit explain() überprüfen
Führen Sie Ihre vollständige find-Kette mit explain('executionStats') aus, um den gesamten Abfrageplan zu überprüfen. Der ideale Plan zeigt: IXSCAN für den Filter, denselben Index-Scan auch für die Sortierung (keine separate SORT-Phase) und einen Wert von nReturned, der Ihrem limit-Wert entspricht. Jede unerwartete COLLSCAN- oder SORT-Phase weist auf einen fehlenden oder ineffektiven Index hin.
const stats = await db.collection('products')
.find({ category: 'electronics', isActive: true })
.sort({ rating: -1, _id: -1 })
.skip(20)
.limit(20)
.explain('executionStats');
const stage = stats.executionStats.executionStages;
console.log('Stage:', stage.stage); // should be LIMIT
console.log('Docs examined:', stats.executionStats.totalDocsExamined);
console.log('Docs returned:', stats.executionStats.nReturned);Kurze Überprüfung
Testen Sie Ihr Verständnis der Konzepte zu MongoDB & NoSQL-Datenbanken aus dieser Lektion.
Zusammenfassung der Lektion
In dieser Lektion haben Sie gelernt: MongoDB führt Filter → Sortierung → Skip → Limit unabhängig von der Reihenfolge der Methodenverkettung immer in dieser Reihenfolge aus, der unterstützende Index sollte zuerst die Gleichheitsfelder und danach die Sortierfelder enthalten, und Paginierungsmetadaten (total, hasNext, hasPrev) sollten gemeinsam mit dem Datenarray zurückgegeben werden. Als Nächstes beschäftigen wir uns mit dem Importieren und Exportieren von Daten mithilfe von mongoimport, mongoexport und Seed-Skripten.
Lerne JavaScript mit einem KI-Tutor — kostenlos
Schreibe und führe echten Code in deinem Browser aus, bekomme sofortige Hilfe von einem 24/7 KI-Tutor und setze dein Lernen im Web oder in der App fort.
- Kurse
- 30
- Lektionen
- 120
Häufig gestellte Fragen
Ist die Lektion „Sort, Skip, Limit und Projektionen kombinieren“ kostenlos?
Ja — der vollständige Text von „Sort, Skip, Limit und Projektionen kombinieren“ ist hier im Web kostenlos zu lesen. Um sie interaktiv zu üben (integrierter Code-Editor und 24/7 KI-Tutor) und den Rest des MongoDB Academy-Kurses freizuschalten, upgrade auf CoddyKit PRO. Der MongoDB Academy-Kurs umfasst insgesamt 4 Lektionen.
Was lerne ich in „Sort, Skip, Limit und Projektionen kombinieren“?
Sie kombinieren Filter, Projektion, Sortierung und Paginierung zu einer vollständigen Abfragekette für einen realistischen Listenendpunkt. Du übst MongoDB Academy mit praktischem Code, den du direkt im Browser ausführst, und ein 24/7 KI-Tutor beantwortet deine Fragen während du die Lektion bearbeitest.
Brauche ich Erfahrung, um MongoDB Academy zu starten?
Keine Vorkenntnisse erforderlich. MongoDB Academy auf CoddyKit ist für Anfänger bis fortgeschrittene Lernende strukturiert, sodass du hier starten oder von Anfang an beginnen und in deinem eigenen Tempo voranschreiten kannst. Dies ist Lektion 4 von 4.
Wie lange dauert die Lektion „Sort, Skip, Limit und Projektionen kombinieren“?
Die meisten CoddyKit-Lektionen dauern etwa 5–10 Minuten. Jede ist kompakt und interaktiv, sodass du stetig Fortschritte machst und genau dort weitermachst, wo du aufgehört hast – im Web und in der App.
Kann ich in dieser MongoDB Academy-Lektion Code schreiben und ausführen?
Ja. Jede MongoDB Academy-Lektion enthält einen integrierten Code-Editor, sodass du echten Code direkt in deinem Browser schreibst und ausführst und sofort KI-Feedback erhältst — ohne lokale Einrichtung erforderlich.
Alle Lektionen in diesem Kurs
- Sortieren mit sort() und mehreren Schlüsseln
- Skip und Limit: Offset-Paginierung
- Keyset-Paginierung mit Bereichsabfragen
- Sort, Skip, Limit und Projektionen kombinieren