MongoDB
 sql >> Base de Dados >  >> NoSQL >> MongoDB

Calcular valor de salto para determinado registro para paginação classificada


Isso é chamado de "encaminhar paginação", que é um conceito que você pode usar para "paginar com eficiência" os resultados em uma direção "avançar" ao usar resultados "classificados".

Lógica JavaScript incluída (porque funciona no shell), mas não é difícil de traduzir.

O conceito em geral:
{ "_id": 1, "a": 3 },
{ "_id": 2, "a": 3 },
{ "_id": 3, "a": 3 },
{ "_id": 4, "a": 2 },
{ "_id": 5, "a": 1 },
{ "_id": 6, "a": 0 }

Considere esses documentos "já classificados" ( por conveniência ) como um exemplo de resultados que queremos "paginar" por "dois" itens por página.

No primeiro caso você faz algo assim:
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
});

Agora aqueles lastVal e lastSeen são algo que você armazena em algo como uma "variável de sessão" que pode ser acessada na próxima solicitação em termos de aplicativos da Web, ou algo semelhante onde não.

O que eles devem conter é o último valor que você estava classificando e a lista de _id "único" valores que foram vistos desde que esse valor não mudou. Conseqüentemente:
lastVal = 3,
lastSeen = [1,2];

O ponto é que, quando a solicitação para a "próxima página" chegar, você deseja usar essas variáveis ​​para algo assim:
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
});

O que isso faz é "excluir" todos os valores de _id que são registrados em lastSeen da lista de resultados, bem como certificar-se de que todos os resultados precisam ser "menores ou iguais a" (ordem decrescente) o lastVal registrado para o campo de classificação "a".

Isso produz os próximos dois resultados na coleção:
{ "_id": 3, "a": 3 },
{ "_id": 4, "a": 2 },

Mas depois de processar nossos valores agora ficam assim:
lastVal = 2,
lastSeen = [4];

Então agora a lógica segue que você não precisa excluir o outro _id valores vistos antes, pois você está realmente procurando apenas valores de "a" que são "menores ou iguais a" o lastVal e como havia apenas "um" _id valor visto nesse valor, então exclua apenas aquele.

Isso, obviamente, produz a próxima página sobre como usar o mesmo código acima:
{ "_id": 5, "a": 1 },
{ "_id": 6, "a": 0 }

Essa é a maneira mais eficiente de "encaminhar a página" pelos resultados em geral e é particularmente útil para a paginação eficiente de resultados "classificados".

Se, no entanto, você quiser "pular" para a página 20 ou ação semelhante em qualquer estágio, isso não é para você. Você está preso ao tradicional .skip() e .limit() abordagem para poder fazer isso pelo "número da página", pois não há outra maneira racional de "calcular" isso.

Portanto, tudo depende de como seu aplicativo está implementando a "paginação" e com o que você pode conviver. O .skip() e .limit() A abordagem sofre o desempenho de "pular" e pode ser evitada usando a abordagem aqui.

Por outro lado, se você quiser "pular para a página", "pular" é sua única opção real, a menos que você queira construir um "cache" de resultados. Mas isso é outra questão inteiramente.