2008-11-23 13 views
42

¿Cómo podría implementar las consultas necesarias para la paginación?Paginación en CouchDB?

Básicamente, cuando se solicita la página 1, obtenga las primeras 5 entradas. Para la página 2, obtenga los próximos 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.

Respuesta

31

El CouchDB Guide tiene una buena discusión de paginación, incluyendo un montón de código de ejemplo, aquí: http://guide.couchdb.org/draft/recipes.html#pagination Aquí es su algoritmo:

  • Solicitud rows_per_page + 1 filas de la vista
  • visualización rows_per_page filas, almacenar última fila como next_startkey
  • Como información de la página, mantenga startkey y next_startkey
  • uso del next_* valores para crear el siguiente enlace, y el uso de los otros para crear el enlace anterior

N.B .: La manera apropiada a buscar páginas en CouchDB es mediante la especificación de una clave de partida, no un índice de inicio, como se 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 fila 11 como la clave de inicio para la página siguiente".

Si espera que varios documentos emitan claves idénticas, necesitará usar startdocid además de startkey para paginar correctamente. El motivo es que startkey solo ya no será suficiente para identificar de manera única una fila. Esos parámetros son inútiles si no proporciona un 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 espera potenciales tienen la misma clave pero diferentes ID de documento. Lo mismo para el .

+2

El problema con este enfoque es que realmente no puede hacer clic en anteriores varias veces, solo una vez. O bien tiene que indexar manualmente TODOS los posibles primero en la página cuando vaya a las páginas siguientes o solo puede retroceder 1 página y luego no tiene ninguna información para ir a otra página anterior. – for3st

+0

Para aquellos que tropiezan aquí y también se encuentran con el dilema de @ for3st, las características naturales de una matriz ayudan a remediar este problema. Con 'push()' ing la página anterior, inicie '_id' en la matriz y puede' pop() 'fácilmente la matriz' _id' cuando haga clic en previous. Como mucho, todo lo que tienes que hacer es realizar un seguimiento de una matriz de enteros. – wootencl

1

Esto es lo que he ocurrió hasta ahora - para obtener los identificadores de todos los mensajes, a continuación, recuperar los elementos reales para el primer número x de ID ..

No es muy eficiente, pero más que recuperando todas las publicaciones, luego tirando la mayor parte de distancia. Dicho esto, para mi sorpresa, parecía funcionar bastante rápido: ejecuté el método posthelper.page() 100 veces y me llevó unos 0,5 segundos.

que no quería publicar esto en la pregunta real, por lo que no iba a influir en las respuestas tanto - 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 
13

El CouchDB HTTP View API da un amplio margen para hacer la paginación de manera eficiente .

El método más simple usaría startkey y count. Count es la cantidad máxima 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 inicie CouchDB. Cuando solicite la vista, también le indicará cuántas entradas hay, lo que le permitirá calcular cuántas páginas habrá si desea mostrarlas a los usuarios.

De modo que la primera solicitud no especificaría una clave 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 la tecla 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 de hacer esto es usar el parámetro de omisión para calcular el documento inicial 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 las entradas sobre las que se 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 salten, más lenta será la solicitud.

+0

Aha! Desde esa página que vinculó: el parámetro de recuento se puede combinar con el "salto = número de filas para omitir". Perfecto. – dbr

+0

He agregado la información anterior a tu respuesta (para mi referencia si nada más), ¡espero que no te importe! – dbr

+2

Lo edité de nuevo. Usar omisión no es una buena forma de hacerlo en la mayoría de los casos. – Kerr