MongoDB Academy · Leçon

$sort, $limit et $skip dans la chaîne de traitement

Les apprenants ordonneront et pagineront les résultats d’agrégation, et comprendront les règles de l’optimiseur qui consistent à placer $match et $sort avant $group.

Leçon 4 sur 413 étapes

$sort, $limit et $skip dans la chaîne de traitement est une leçon MongoDB Academy gratuite sur CoddyKit. Ceci est la leçon 4 sur 4. Tu peux lire la leçon complète ci-dessous gratuitement — puis la pratiquer en direct dans le navigateur avec un éditeur de code intégré et un tuteur IA 24/7. Elle fait partie du parcours d'apprentissage MongoDB Academy, et ta progression se synchronise sur le web et l'application CoddyKit. Le cours MongoDB Academy comprend 4 leçons au total.

Présentation : trier et paginer les résultats

Trois étapes du pipeline d’agrégation contrôlent l’ordre et le volume des résultats : $sort trie les documents selon un ou plusieurs champs, $limit ne conserve que les N premiers documents et $skip ignore les N premiers documents. Ensemble, elles permettent d’implémenter le tri et la pagination. Il est essentiel de comprendre où les placer dans le pipeline, car leur position a un impact important sur les performances.

L’étape $sort

L’étape $sort trie les documents selon les valeurs d’un ou plusieurs champs. Utilisez 1 pour un ordre croissant et -1 pour un ordre décroissant. Lorsque plusieurs champs sont indiqués, les documents sont d’abord triés selon le premier champ, puis selon le deuxième en cas d’égalité, et ainsi de suite, exactement comme pour un tri à plusieurs clés en SQL ou avec find().sort() de MongoDB.

// Sort by revenue descending, then alphabetically by name for ties
db.products.aggregate([
  { $group: { _id: '$category', revenue: { $sum: '$price' } } },
  { $sort: { revenue: -1, _id: 1 } }  // revenue desc, category name asc
]);

$sort et utilisation des index

Lorsque $sort est la première étape du pipeline (ou qu’il suit un $match utilisant un index), MongoDB peut utiliser un index pour effectuer le tri, évitant ainsi entièrement un tri en mémoire. Lorsque $sort apparaît après des étapes qui produisent de nouveaux champs, comme $group ou $project, aucun index n’est disponible et MongoDB effectue un tri en mémoire. Les tris en mémoire volumineux (plus de 100 Mo) nécessitent allowDiskUse: true.

// Index-backed sort: $sort on indexed field before any transformation
db.orders.aggregate([
  { $match: { userId: 'u1' } },
  { $sort: { createdAt: -1 } }  // if createdAt is indexed, no in-memory sort
]);

// In-memory sort: $sort after $group (computed field, no index)
db.orders.aggregate([
  { $group: { _id: '$userId', total: { $sum: '$amount' } } },
  { $sort: { total: -1 } }  // in-memory: 'total' is a computed field
]);

L’étape $limit

$limit ne transmet en aval que les N premiers documents et ignore les autres. Son fonctionnement est simple : transmettez un entier indiquant le nombre maximal de documents à laisser passer. Placer $limit avant des étapes coûteuses comme $lookup réduit considérablement le nombre de jointures ou de recherches effectuées. Demandez-vous toujours : « Puis-je limiter plus tôt ? »

// Top 10 best-selling products
db.orders.aggregate([
  { $group: { _id: '$productId', sold: { $sum: '$qty' } } },
  { $sort: { sold: -1 } },
  { $limit: 10 },  // only top 10 pass through
  // Only 10 lookups instead of thousands:
  { $lookup: { from: 'products', localField: '_id', foreignField: '_id', as: 'product' } }
]);

L’étape $skip

$skip ignore les N premiers documents du flux. C'est l'équivalent, pour les agrégations, de la pagination par décalage : la page 2 commence avec skip 10 (en supposant une limite de 10 éléments par page). $skip vient toujours après $sort afin de produire des résultats cohérents : ignorer des documents non triés donne des pages imprévisibles. Comme avec OFFSET en SQL, $skip est lent pour les décalages importants, car MongoDB doit tout de même traiter tous les documents ignorés.

const PAGE = 2;
const PAGE_SIZE = 10;

db.articles.aggregate([
  { $match: { status: 'published' } },
  { $sort: { publishedAt: -1 } },
  { $skip: (PAGE - 1) * PAGE_SIZE },  // skip page 1's 10 docs
  { $limit: PAGE_SIZE }               // take page 2's 10 docs
]);

Optimiseur : fusion de $sort et $limit

L'optimiseur d'agrégation de MongoDB détecte lorsqu'une étape $sort est immédiatement suivie d'une étape $limit et les fusionne en un tri des N premiers éléments. Au lieu de trier tous les documents puis d'en supprimer la plupart, MongoDB conserve uniquement les N meilleurs candidats dans une file de priorité pendant le tri, ce qui utilise une mémoire en O(N) plutôt qu'une mémoire en O(total). Cette optimisation est automatique : il vous suffit d'écrire $sort suivi de $limit.

// This pattern triggers the top-N sort optimisation
db.reviews.aggregate([
  { $match: { productId: 'p1' } },
  { $sort: { rating: -1, helpful: -1 } },  // sort
  { $limit: 5 }   // $sort + $limit merged into top-5 sort internally
]);
// MongoDB never sorts ALL reviews; it tracks only the best 5

Optimiseur : réorganisation de $match et $sort

L'optimiseur d'agrégation déplace également automatiquement une étape $match plus tôt dans le pipeline lorsqu'il peut le faire sans risque. Par exemple, si $sort apparaît avant $match sur un champ que $sort n'a pas calculé, l'optimiseur place $match avant $sort afin de réduire le nombre de documents à trier. Vous pouvez observer les modifications de l'optimiseur dans la sortie de explain().

// You write:
db.orders.aggregate([
  { $sort: { amount: -1 } },
  { $match: { status: 'completed' } }  // optimizer moves this BEFORE $sort
]);

// Optimized execution (equivalent to):
db.orders.aggregate([
  { $match: { status: 'completed' } },  // fewer docs to sort
  { $sort: { amount: -1 } }
]);

Combiner les quatre : un endpoint complet de liste

Un endpoint d'API réaliste qui répertorie des produits avec filtrage, tri et pagination combine $match, $sort, $skip et $limit dans le bon ordre. Le schéma est toujours le suivant : filtrer → trier → ignorer → limiter. Cet ordre garantit que MongoDB utilise les index pour le filtrage et, lorsque c'est possible, pour le tri, avant de supprimer les documents inutiles.

async function getProducts({ category, sort = 'price', page = 1, pageSize = 20 }) {
  return db.products.aggregate([
    { $match: { category, inStock: true } },   // 1. filter
    { $sort: { [sort]: 1 } },                  // 2. sort
    { $skip: (page - 1) * pageSize },          // 3. offset
    { $limit: pageSize }                       // 4. take page
  ]).toArray();
}

Performances de $skip avec les décalages importants

Le problème fondamental de $skip est que MongoDB doit tout de même traiter et supprimer chaque document ignoré. À la page 1000, avec 20 éléments par page, MongoDB supprime 19 980 documents avant d'en renvoyer 20. Le traitement devient progressivement plus lent à mesure que les pages sont éloignées. Pour les API de recherche ou de flux accessibles au public, où les utilisateurs dépassent rarement la page 5 à 10, la pagination par décalage convient. Pour une pagination profonde à haute fréquence, la pagination par curseur est nécessaire.

// Page 1000 is SLOW: MongoDB processes and discards 19,980 docs
db.posts.aggregate([
  { $sort: { createdAt: -1 } },
  { $skip: 19980 },  // 999 * 20
  { $limit: 20 }
]);

// Keyset pagination: always fast regardless of page depth
db.posts.aggregate([
  { $match: { createdAt: { $lt: lastSeenTimestamp } } },  // cursor
  { $sort: { createdAt: -1 } },
  { $limit: 20 }
]);

Limite de mémoire de $sort et allowDiskUse

Un $sort en mémoire dans le pipeline d'agrégation est limité à 100 MB par défaut. Si le tri dépasse cette limite, le pipeline échoue avec une erreur QueryExceededMemoryLimitNoDiskUseAllowed. Transmettez { allowDiskUse: true } comme deuxième argument à aggregate() pour autoriser le débordement sur disque. Vous pouvez également appliquer un $match tôt dans le pipeline ou utiliser un index adapté afin de réduire la taille des données à trier.

// Enable disk use for large sorts
db.events.aggregate(
  [
    { $match: { year: 2024 } },
    { $sort: { timestamp: -1 } },
    { $group: { _id: '$userId', events: { $push: '$type' } } }
  ],
  { allowDiskUse: true }  // allows spilling to disk
);

Obtenir le nombre total avec les résultats

Un schéma courant pour une API consiste à renvoyer à la fois les résultats paginés et le nombre total en un seul aller-retour vers la base de données. Utilisez $facet pour diviser le pipeline en deux branches parallèles : l'une pour les résultats avec $skip/$limit, l'autre pour $count. Cela évite deux appels d'agrégation distincts et est plus efficace que de compter séparément tous les documents.

db.products.aggregate([
  { $match: { category: 'electronics' } },
  { $sort: { price: 1 } },
  { $facet: {
    // Branch 1: paginated results
    data: [
      { $skip: 0 },
      { $limit: 20 }
    ],
    // Branch 2: total count
    total: [
      { $count: 'count' }
    ]
  }}
]);
// Output: { data: [...20 docs...], total: [{ count: 348 }] }

Vérification rapide

Vérifiez votre compréhension de $sort, $limit et $skip dans le pipeline d'agrégation.

Récapitulatif de la leçon

Dans cette leçon, vous avez appris que : $sort ordonne les documents et bénéficie de l'utilisation d'index lorsqu'il est placé tôt, que $limit prend les N premiers documents et fusionne avec $sort pour effectuer un tri efficace des N premiers éléments, et que $skip met en œuvre la pagination par décalage, mais devient moins performant avec les grands décalages. Nous allons maintenant étudier des étapes d'agrégation avancées, notamment $lookup pour effectuer des jointures entre collections.

Gratuit pour commencer

Apprends JavaScript avec un tuteur IA — gratuit

Écris et exécute du vrai code dans ton navigateur, obtiens de l'aide instantanée d'un tuteur IA disponible 24h/24, et reprends là où tu t'es arrêté sur le web ou dans l'app.

Cours
30
Leçons
120

Questions Fréquemment Posées

La leçon « $sort, $limit et $skip dans la chaîne de traitement » est-elle gratuite ?

Oui — le texte complet de « $sort, $limit et $skip dans la chaîne de traitement » est gratuit à lire ici sur le web. Pour la pratiquer de manière interactive (un éditeur de code intégré et un tuteur IA 24/7) et déverrouiller le reste du cours MongoDB Academy, passe à CoddyKit PRO. Le cours MongoDB Academy comprend 4 leçons au total.

Qu'est-ce que j'apprendrai dans « $sort, $limit et $skip dans la chaîne de traitement » ?

Les apprenants ordonneront et pagineront les résultats d’agrégation, et comprendront les règles de l’optimiseur qui consistent à placer $match et $sort avant $group. Tu pratiques MongoDB Academy avec du code pratique que tu exécutes directement dans le navigateur, et un tuteur IA 24/7 répond à tes questions au fur et à mesure que tu avances dans la leçon.

Dois-je avoir de l'expérience pour commencer MongoDB Academy ?

Aucune expérience préalable n'est requise. MongoDB Academy sur CoddyKit est structuré pour les débutants jusqu'aux apprenants avancés, donc tu peux commencer ici ou depuis le début et avancer à ton rythme. Ceci est la leçon 4 sur 4.

Combien de temps prend la leçon « $sort, $limit et $skip dans la chaîne de traitement » ?

La plupart des leçons CoddyKit prennent environ 5–10 minutes. Chacune est courte et interactive, tu progresses régulièrement et tu repiques exactement où tu t'es arrêté sur le web et l'app.

Peux-tu écrire et exécuter du code dans cette leçon MongoDB Academy ?

Oui. Chaque leçon MongoDB Academy inclut un éditeur de code intégré, tu écris et exécutes du vrai code directement dans ton navigateur et tu reçois des retours IA instantanés — aucune configuration locale requise.

Toutes les leçons de ce cours

  1. Concepts des chaînes de traitement : étapes, opérateurs et expressions
  2. $match et $project : filtrer et remodeler
  3. $group : agréger et calculer des totaux
  4. $sort, $limit et $skip dans la chaîne de traitement
← Retour à MongoDB Academy