MongoDB Academy · Les

Skip en limit: paginering met offsets

U implementeert traditionele paginering met paginanummers met skip() en limit() en meet de prestat kosten hiervan bij grote collecties.

Les 2 van 413 stappen

Skip en limit: paginering met offsets is een gratis MongoDB Academy-les op CoddyKit. Dit is les 2 van 4. Je kunt de volledige les hieronder gratis lezen en daarna in de browser praktisch oefenen met een ingebouwde code-editor en een AI-begeleider die 24/7 beschikbaar is. Deze les maakt deel uit van het leertraject MongoDB Academy. Je voortgang wordt gesynchroniseerd op het web en in de CoddyKit-app. De cursus MongoDB Academy bevat in totaal 4 lessen.

Wat is paginering op basis van een offset?

Paginering op basis van een offset—ook wel paginering op paginanummer genoemd—verdeelt resultaten in pagina's met een vaste grootte en gebruikt een paginanummer om te bepalen hoe ver in de resultatenset moet worden begonnen. Op pagina 1 staan items 1-20, op pagina 2 items 21-40, enzovoort. In MongoDB wordt dit geïmplementeerd met skip() om eerdere resultaten over te slaan en limit() om het aantal documenten per pagina te beperken.

skip() en limit() gebruiken

limit(N) geeft de cursor opdracht om maximaal N documenten te retourneren. skip(N) geeft MongoDB opdracht om de eerste N documenten over te slaan voordat resultaten worden geretourneerd. Samen implementeren ze paginering op paginanummer: gebruik voor pagina P met S items per pagina skip((P-1)*S) en limit(S).

const PAGE = 3;
const PAGE_SIZE = 20;

// Page 3 of 20 results per page
const products = await db.collection('products')
  .find({ isActive: true })
  .sort({ createdAt: -1 })
  .skip((PAGE - 1) * PAGE_SIZE)  // skip 40 docs (pages 1 and 2)
  .limit(PAGE_SIZE)               // return next 20
  .toArray();

console.log('Page 3 results:', products.length);

Het totale aantal pagina's tellen

Voor paginering op basis van een offset is meestal het totale aantal documenten nodig om paginanummers in de gebruikersinterface weer te geven. Gebruik countDocuments(filter) om overeenkomende documenten te tellen voordat je de paginering toepast. Voer de telling en de query met paginering parallel uit om extra wachttijd te voorkomen. Het totale aantal gedeeld door de paginagrootte, naar boven afgerond, geeft het totale aantal pagina's.

const filter = { isActive: true };

const [total, results] = await Promise.all([
  db.collection('products').countDocuments(filter),
  db.collection('products')
    .find(filter)
    .sort({ createdAt: -1 })
    .skip((PAGE - 1) * PAGE_SIZE)
    .limit(PAGE_SIZE)
    .toArray()
]);

const totalPages = Math.ceil(total / PAGE_SIZE);
console.log('Total:', total, 'Pages:', totalPages);

De verborgen kosten van skip()

MongoDB implementeert skip() door de eerste N documenten te scannen en weg te gooien. Zelfs met een index moet MongoDB N indexvermeldingen doorlopen en tellen voordat resultaten worden geretourneerd. Op pagina 1 is skip 0 en is de bewerking snel. Op pagina 500 met 20 items per pagina is skip 9980: MongoDB moet bijna 10.000 vermeldingen doorlopen om alleen te bepalen waar pagina 500 begint. Dit is het belangrijkste prestatieprobleem van paginering op basis van een offset.

Complexiteit van query's: O(skip + limit)

De uitvoeringstijd van een query met skip en limit groeit lineair met de hoeveelheid die wordt overgeslagen. De kosten van de query zijn O(skip + limit): de server moet skip documenten onderzoeken voordat hij limit documenten retourneert. Voor pagina 1 is dit O(20); voor pagina 1000 met 20 items per pagina is dit O(20020). Naarmate gebruikers naar hogere paginanummers navigeren, worden query's steeds trager en loopt de uitvoeringstijd bij grote collecties vaak op van milliseconden tot seconden.

Wanneer paginering op basis van een offset aanvaardbaar is

Ondanks de prestatiebeperkingen is paginering op basis van een offset aanvaardbaar in deze situaties: (1) de collectie bevat minder dan enkele duizenden documenten; (2) gebruikers navigeren zelden verder dan de eerste paar pagina's; (3) de functie vereist dat je rechtstreeks naar een paginanummer kunt springen, bijvoorbeeld 'ga naar pagina 47'. Veel beheerdersdashboards en zoekresultaten met weinig pagina's passen in dit profiel. Gebruik paginering op basis van sleutels voor oneindig scrollen of grote gegevensverzamelingen.

Een API-eindpunt met paginering op basis van een offset implementeren

Een typisch REST-lijst-eindpunt accepteert de queryparameters page en limit, valideert ze en past overeenkomstig skip en limit toe. Beperk de maximale limiet altijd om te voorkomen dat clients duizenden documenten in één aanroep opvragen, waardoor het servergeheugen uitgeput kan raken.

// Express route: GET /api/products?page=2&limit=20
async function listProducts(req, res) {
  const page  = Math.max(1, parseInt(req.query.page)  || 1);
  const limit = Math.min(100, parseInt(req.query.limit) || 20); // cap at 100
  const skip  = (page - 1) * limit;

  const [total, items] = await Promise.all([
    Product.countDocuments({ isActive: true }),
    Product.find({ isActive: true }).sort('-createdAt').skip(skip).limit(limit).lean()
  ]);

  res.json({ page, limit, total, totalPages: Math.ceil(total / limit), items });
}

Problemen met gegevensconsistentie bij paginering op basis van een offset

Paginering op basis van een offset heeft een subtiel probleem met de correctheid: als er tussen pagina-aanvragen documenten worden ingevoegd of verwijderd, kunnen items van positie veranderen in de gesorteerde resultatenset. Een document dat tussen pagina 1 en pagina 2 wordt ingevoegd, schuift elk volgend document op, waardoor één item op beide pagina's kan verschijnen (duplicaat) of volledig kan worden overgeslagen. Dit heet het probleem van verschuivende pagina's en is inherent aan paginering op basis van een offset.

Geschat tegenover exact aantal

Voor zeer grote collecties kan countDocuments(filter) traag zijn omdat de index wordt gescand. Een alternatief is estimatedDocumentCount(). Dit heeft complexiteit O(1), maar telt alle documenten in de collectie zonder een filter toe te passen. Voor eenvoudige gevallen waarin je het totaal zonder filter wilt weten, is de schatting veel sneller. Overweeg voor gefilterde tellingen in grote collecties de telling te cachen of de gefacetteerde zoekfunctie van Atlas te gebruiken.

// O(1) but no filter support
const approxTotal = await db.collection('products').estimatedDocumentCount();

// Exact count with filter (slower on large collections)
const exactTotal = await db.collection('products').countDocuments({ isActive: true });

skip/limit combineren met projecties

Combineer paginering voor lijst-eindpunten altijd met een beperkte projectie. Alle velden ophalen tijdens het pagineren gaat voorbij aan het doel: je betaalt nog steeds voor het overdragen van volledige documentgegevens voor elke pagina. Een projectie die alleen samenvattingsvelden retourneert (naam, prijs, miniatuur) vermindert de bandbreedte met 80-95% vergeleken met het ophalen van volledige documenten, waardoor paginering bij grotere offsets haalbaar wordt.

const SUMMARY = { _id: 1, name: 1, price: 1, thumbnailUrl: 1, rating: 1 };

const items = await db.collection('products')
  .find({ isActive: true })
  .projection(SUMMARY)
  .sort({ rating: -1 })
  .skip((PAGE - 1) * PAGE_SIZE)
  .limit(PAGE_SIZE)
  .toArray();

Wanneer overstappen op paginering op basis van sleutels

Stap van paginering op basis van een offset over op paginering op basis van sleutels (cursorpaginering) wanneer gebruikers oneindig door resultaten scrollen (er zijn geen paginanummers nodig), de collectie meer dan 100.000 documenten bevat, laadtijden merkbaar toenemen bij hogere paginanummers of gegevens vaak veranderen tussen pagina-aanvragen. Paginering op basis van sleutels heeft altijd complexiteit O(log n), ongeacht de positie in de resultatenset, omdat deze een bereikquery op een geïndexeerd veld gebruikt in plaats van skip.

Korte controle

Test je begrip van de concepten uit deze les over MongoDB en NoSQL-databases.

Samenvatting van de les

In deze les heb je geleerd dat paginering op basis van een offset skip((page-1)*size) en limit(size) gebruikt om een pagina op te halen, dat skip() documenten scant en weggooit, waardoor diepe pagina's steeds trager worden en dat paginering op basis van een offset geschikt is voor kleine collecties of weinig pagina's, maar paginering op basis van sleutels beter schaalt. Hierna implementeren we paginering op basis van sleutels met bereikquery's voor consistente prestaties met complexiteit O(log n).

Gratis beginnen

Leer JavaScript met een AI-tutor — gratis

Schrijf echte code en voer die uit in je browser, krijg direct hulp van een AI-tutor die 24/7 beschikbaar is en ga verder waar je gebleven bent op het web of in de app.

Cursussen
30
Lessen
120

Veelgestelde vragen

Is de les “Skip en limit: paginering met offsets” gratis?

Ja — de volledige tekst van “Skip en limit: paginering met offsets” kun je hier gratis op het web lezen. Als je interactief wilt oefenen met een ingebouwde code-editor en een AI-begeleider die 24/7 beschikbaar is, en de rest van de cursus MongoDB Academy wilt ontgrendelen, kun je upgraden naar CoddyKit PRO. De cursus MongoDB Academy bevat in totaal 4 lessen.

Wat leer ik in “Skip en limit: paginering met offsets”?

U implementeert traditionele paginering met paginanummers met skip() en limit() en meet de prestat kosten hiervan bij grote collecties. Je oefent met MongoDB Academy door code rechtstreeks in de browser uit te voeren. Een AI-begeleider die 24/7 beschikbaar is beantwoordt je vragen terwijl je de les doorwerkt.

Heb ik ervaring nodig om met MongoDB Academy te beginnen?

Ervaring vooraf is niet nodig. MongoDB Academy op CoddyKit is opgebouwd voor beginners tot gevorderden, zodat je hier of bij het begin kunt starten en in je eigen tempo kunt leren. Dit is les 2 van 4.

Hoe lang duurt de les “Skip en limit: paginering met offsets”?

De meeste lessen van CoddyKit duren ongeveer 5–10 minuten. Elke les is kort en interactief, zodat je gestaag vooruitgaat en op het web en in de app precies verdergaat waar je was gebleven.

Kan ik code schrijven en uitvoeren in deze les over MongoDB Academy?

Ja. Elke les over MongoDB Academy bevat een ingebouwde code-editor, zodat je rechtstreeks in je browser echte code kunt schrijven en uitvoeren en direct feedback van AI krijgt — lokale installatie is niet nodig.

Alle lessen in deze cursus

  1. Sorteren met sort() en meerdere sleutels
  2. Skip en limit: paginering met offsets
  3. Keyset-paginering met range-query's
  4. Sort, skip, limit en projections combineren
← Terug naar MongoDB Academy