sql >> Base de Datos >  >> NoSQL >> MongoDB

Calcule el valor de omisión para un registro dado para la paginación ordenada

Esto se llama "paginación hacia adelante", que es un concepto que puede usar para "paginar eficientemente" a través de los resultados en una dirección "hacia adelante" cuando se usan resultados "ordenados".

Lógica de JavaScript incluida (porque funciona en el shell), pero no es difícil de traducir.

El concepto en general:

{ "_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 esos documentos "ya ordenados" (por conveniencia) como un ejemplo de los resultados que queremos "paginar" por "dos" elementos por página.

En primera instancia, haces algo como esto:

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
});

Ahora esos lastVal y lastSeen son algo que almacena en algo como una "variable de sesión" a la que se puede acceder en la próxima solicitud en términos de aplicaciones web, o algo similar donde no.

Sin embargo, lo que deberían contener es el último valor que estabas clasificando y la lista de _id "únicos". valores que se vieron ya que ese valor no cambió. Por lo tanto:

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

El punto es que cuando aparece la solicitud de la "página siguiente", entonces desea usar esas variables para algo como esto:

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
});

Lo que hace es "excluir" todos los valores de _id que se registran en lastSeen de la lista de resultados, así como asegúrese de que todos los resultados deben ser "menores o iguales a" (orden descendente) el lastVal registrado para el campo de clasificación "a".

Esto produce los siguientes dos resultados en la colección:

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

Pero después de procesar nuestros valores ahora se ven así:

lastVal = 2,
lastSeen = [4];

Entonces ahora la lógica sigue que no necesita excluir el otro _id valores vistos antes ya que solo está buscando valores de "a" que sean "menores o iguales a" el lastVal y como solo había "uno" _id el valor visto en ese valor solo lo excluye.

Esto, por supuesto, produce la siguiente página sobre el uso del mismo código que el anterior:

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

Esa es la forma más eficiente de "reenviar página" a través de los resultados en general y es particularmente útil para la paginación eficiente de resultados "ordenados".

Sin embargo, si desea "saltar" a la página 20 o una acción similar en cualquier etapa, entonces esto no es para ti. Estás atascado con el tradicional .skip() y .limit() enfoque para poder hacer esto por "número de página" ya que no hay otra forma racional de "calcular" esto.

Entonces, todo depende de cómo su aplicación implemente la "paginación" y con qué pueda vivir. El .skip() y .limit() El enfoque sufre el rendimiento de "saltar" y se puede evitar usando el enfoque aquí.

Por otro lado, si desea "saltar a la página", "saltar" es su única opción real, a menos que desee crear un "caché" de resultados. Pero ese es otro tema completamente diferente.