sql >> Database >  >> NoSQL >> MongoDB

Bereken de skip-waarde voor een bepaald record voor gesorteerde paging

Dit wordt "forward paging" genoemd, een concept dat u kunt gebruiken om "efficiënt door de resultaten te bladeren" in een "voorwaartse" richting wanneer u "gesorteerde" resultaten gebruikt.

JavaScript-logica inbegrepen (omdat het in de shell werkt), maar niet moeilijk te vertalen.

Het concept in het algemeen:

{ "_id": 1, "a": 3 },
{ "_id": 2, "a": 3 },
{ "_id": 3, "a": 3 },
{ "_id": 4, "a": 2 },
{ "_id": 5, "a": 1 },
{ "_id": 6, "a": 0 }

Beschouw die "reeds gesorteerde" documenten (voor het gemak) als een voorbeeld van resultaten die we willen "pagina's" met "twee" items per pagina.

In eerste instantie doe je zoiets als dit:

var lastVal = null,
    lastSeen = [];

db.collection.find().sort({ "a": -1 }).limit(2).forEach(function(doc) {
    if ( lastVal != doc.a ) {
        lastSeen = [];
    }
    lastVal = doc.a;
    lastSeen.push( doc._id );
    // do something useful with each document matched
});

Nu die lastVal en lastSeen zijn iets dat u opslaat in zoiets als een "sessievariabele" dan toegankelijk is op het volgende verzoek in termen van webapplicaties, of anderszins iets dergelijks waar niet.

Wat ze echter zouden moeten bevatten, is de allerlaatste waarde waarop u sorteerde en de lijst met "unieke" _id waarden die werden gezien sinds die waarde niet veranderde. Vandaar:

lastVal = 3,
lastSeen = [1,2];

Het punt is dat wanneer het verzoek voor de "volgende pagina" binnenkomt, je die variabelen voor zoiets als dit wilt gebruiken:

var lastVal = 3,
    lastSeen = [1,2];

db.collection.find({ 
    "_id": { "$nin": lastSeen }, 
    "a": { "$lte": lastVal }
}).sort({ "a": -1 }).limit(2).forEach(function(doc) {
    if ( lastVal != doc.a ) {
        lastSeen = [];
    }
    lastVal = doc.a;
    lastSeen.push( doc._id );
    // do something useful with each document matched
});

Wat dat doet is "uitsluiten" alle waarden van _id die zijn vastgelegd in lastSeen uit de lijst met resultaten, en zorg ervoor dat alle resultaten "kleiner dan of gelijk aan" (aflopende volgorde) de lastVal moeten zijn opgenomen voor het sorteerveld "a".

Dit levert de volgende twee resultaten op in de verzameling:

{ "_id": 3, "a": 3 },
{ "_id": 4, "a": 2 },

Maar na verwerking zien onze waarden er nu zo uit:

lastVal = 2,
lastSeen = [4];

Dus nu volgt de logica dat je de andere _id . niet hoeft uit te sluiten waarden die eerder zijn gezien, omdat u alleen echt op zoek bent naar waarden van "a" dan zijn "kleiner dan of gelijk aan" de lastVal en aangezien er maar "één" was _id waarde gezien bij die waarde, sluit die dan alleen uit.

Dit levert natuurlijk de volgende pagina op over het gebruik van dezelfde code als net hierboven:

{ "_id": 5, "a": 1 },
{ "_id": 6, "a": 0 }

Dat is de meest efficiënte manier om door resultaten in het algemeen "door te bladeren" en is vooral handig voor het efficiënt doorbladeren van "gesorteerde" resultaten.

Als u echter wilt "springen" naar pagina 20 of soortgelijke actie in welk stadium dan ook, dan is dit niets voor jou. Je zit vast met de traditionele .skip() en .limit() benadering om dit op "paginanummer" te kunnen doen, aangezien er geen andere rationele manier is om dit te "berekenen".

Het hangt dus allemaal af van hoe uw toepassing "paging" implementeert en waar u mee kunt leven. De .skip() en .limit() aanpak lijdt onder de prestatie van "overslaan" en kan worden vermeden door de aanpak hier te gebruiken.

Aan de andere kant, als je "naar pagina springen" wilt, dan is "overslaan" je enige echte optie, tenzij je een "cache" met resultaten wilt bouwen. Maar dat is een heel ander probleem.




  1. Meteor:Onverwachte mongo-exitcode 100. Opnieuw opstarten. Kan mongo-server niet starten

  2. MongoDB toevoegen aan deelname aan verzamelingsveld vanaf de basis

  3. Hoe te herstellen van een MongoDB-terugdraaiing?

  4. Mac(os x):Is er een manier om ALLEEN redis-cli te installeren?