Pregunta
¿Cómo haría para implementar las consultas requeridas para la paginación?
Básicamente, cuando se solicita la página 1, obtenga las primeras 5 entradas. Para la página 2, obtenga los siguientes 5 y así sucesivamente.
Planeo usar esto a través del módulo couchdb-python, pero eso no debería hacer ninguna diferencia en la implementación.
Solución
La Guía CouchDB tiene una buena discusión sobre la paginación, incluidos muchos códigos de muestra, aquí: http://guide.couchdb.org/draft/recipes.html#pagination Aquí está su algoritmo:
- Solicite
rows_per_page + 1
filas de la vista - Mostrar
rows_per_page
filas, almacenar la última fila comonext_startkey
- Como información de la página, mantenga
startkey
ynext_startkey
- Use los valores
next_ *
para crear el siguiente enlace, y use los otros para crear el enlace anterior
N.B .: La forma correcta de recuperar páginas en CouchDB es especificando una clave de inicio, no un índice de inicio como podría pensar. Pero, ¿cómo sabes en qué tecla comenzar la segunda página? La solución inteligente: " En lugar de solicitar 10 filas para una página, solicita 11 filas, pero muestra solo 10 y usa los valores en la 11ª fila como la tecla de inicio para la página siguiente. & Quot;
Si espera que varios documentos emitan claves idénticas, deberá usar startdocid
además de startkey
para paginar correctamente. La razón es que startkey
solo ya no será suficiente para identificar de forma exclusiva una fila. Esos parámetros son inútiles si no proporciona una startkey
. De hecho, CouchDB primero mirará el parámetro startkey
, luego usará el parámetro startdocid
para redefinir aún más el comienzo del rango si múltiples filas de mira potenciales tienen la misma clave pero diferentes ID de documentos. Lo mismo para el enddocid
.
Otros consejos
El CouchDB HTTP View API ofrece un amplio margen para realizar la paginación de manera eficiente.
El método más simple usaría startkey
y count
. El recuento es el número máximo de entradas que CouchDB devolverá para esa solicitud de vista, algo que depende de su diseño, y la tecla de inicio es donde desea que comience CouchDB. Cuando solicite la vista, también le indicará cuántas entradas hay, lo que le permite calcular cuántas páginas habrá si desea mostrarlas a los usuarios.
Entonces, la primera solicitud no especificaría una tecla de inicio, solo el recuento de la cantidad de entradas que desea mostrar. Luego puede anotar la clave de la última entrada devuelta y usarla como clave de inicio para la página siguiente. En esta forma simple, obtendrá una superposición, donde la última entrada de una página es la primera de la siguiente. Si esto no es deseable, es trivial simplemente no mostrar la última entrada de la página.
Un método más simple para hacerlo es usar el parámetro skip para elaborar el documento de inicio de la página, sin embargo, este método debe usarse con precaución. El parámetro de omisión simplemente hace que el motor interno no devuelva entradas sobre las que está iterando. Si bien esto proporciona el comportamiento deseado, es mucho más lento que encontrar el primer documento para la página por clave. Cuantos más documentos se omitan, más lenta será la solicitud.
Esto es lo que se me ocurrió hasta ahora: para obtener los identificadores de todas las publicaciones, luego recuperar los elementos reales para el primer número x de ID ...
No es terriblemente eficiente, pero más que recuperar todas las publicaciones y luego tirar la mayor parte de la basura. Dicho esto, para mi sorpresa, parecía funcionar bastante rápido: ejecuté el método posthelper.page ()
100 veces y me tomó aproximadamente 0.5 segundos.
No quería publicar esto en la pregunta real, por lo que no influiría tanto en las respuestas: aquí está el código:
allPostsUuid = """
function(doc) {
if(doc.type == 'post'){
emit(doc._id, null);
}
}
"""
class PostsHelper:
def __init__(self):
server = Server(config.dbhost)
db = server[config.dbname]
return db
def _getPostByUuid(self, uuid):
return self.db.get(uuid)
def page(self, number = 1):
number -= 1 # start at zero offset
start = number * config.perPage
end = start + config.perPage
allUuids = [
x.key for x in self.db.query(allPostsUuid)
]
ret = [
self._getPostByUuid(x) for x in allUuids[start : end]
]
if len(ret) == 0:
raise Error404("Invalid page (%s results)" % (len(allUuids)))
else:
return ret
-
Aquí abajo está la forma recursiva que encontré:
Toma dos variables
var lastOffset = 0; var counter = 0;
function someRecursive(lastOffset,counter) {
queryView(db, whereClause).then(result => {
var rows_per_page = 5;
//formula below
var page = Math.floor((lastOffset == 0 ? 0: (result.offset - lastOffset) +
(rows_per_page * counter)) / rows_per_page) + 1;
var skip = page * rows_per_page;
if (somerecursionexitcondition) {
counter = lastOffset == 0 ? lastOffset: counter + 1;
lastOffset =result.offset;
someRecursive(lastOffset, counter).then(result => {
resolve();
});
});
}