2008-11-23 6 views
42

Comment aborder la mise en œuvre des requêtes requises pour la pagination?Pagination dans CouchDB?

Fondamentalement, lorsque la page 1 est demandée, obtenez les 5 premières entrées. Pour la page 2, obtenez les 5 prochaines et ainsi de suite.

Je prévois de l'utiliser via le module couchdb-python, mais cela ne devrait pas faire de différence pour l'implémentation.

Répondre

31

Le CouchDB Guide a une bonne discussion sur la pagination, y compris beaucoup d'exemples de code, voici: http://guide.couchdb.org/draft/recipes.html#pagination Voici leur algorithme:

  • Demande rows_per_page + 1 lignes de la vue
  • Afficher rows_per_page lignes, magasin dernière ligne comme next_startkey
  • Comme les informations de page, gardez startkey et next_startkey
  • Utilisez le next_* valeurs pour créer le lien suivant, et utiliser les autres pour créer le lien précédent

N.B. .: La façon de chercher des pages dans CouchDB est en spécifiant une clé de départ, pas un index de départ comme vous pourriez penser. Mais comment savez-vous quelle touche pour démarrer la deuxième page?La solution astucieuse: "Au lieu de demander 10 lignes pour une page, vous demandez 11 lignes, mais n'en affichez que 10 et utilisez les valeurs de la 11e ligne comme clé de départ pour la page suivante."

Si vous prévoyez que plusieurs documents émettent des clés identiques, vous devez utiliser startdocid en plus de startkey pour paginer correctement. La raison en est que startkey seul ne suffira plus pour identifier une ligne de façon unique. Ces paramètres sont inutiles si vous ne fournissez pas un startkey. En fait, CouchDB examinera d'abord le paramètre startkey, puis utilisera le paramètre startdocid pour redéfinir le début de la plage si plusieurs lignes de démarrage potentielles ont la même clé mais des ID de document différents. Même chose pour le .

+2

Le problème avec cette approche est que vous ne pouvez pas vraiment cliquer sur les précédentes fois, une seule fois. Vous devez soit indexer manuellement TOUTES les premières pages possibles lorsque vous allez aux pages suivantes ou vous ne pouvez revenir en arrière qu'une seule page et vous n'avez alors aucune information pour passer à une autre page. – for3st

+0

Pour ceux qui trébuchent ici et se heurtent également au dilemme @ for3st, les caractéristiques naturelles d'un tableau aident à remédier à ce problème. En poussant() la page précédente commence '_id' dans le tableau, vous pouvez facilement' pop() 'le tableau' _id' lorsque vous cliquez sur précédent. Tout ce que vous avez à faire est de suivre un tableau d'entiers. – wootencl

1

C'est ce que je suis venu avec à ce jour - pour obtenir les IDs de tous les messages, puis récupérer les éléments réels pour le premier numéro de x d'ID ..

Il est pas très efficace, mais plus que récupérer tous les messages, puis jeter la plupart de la partie. Cela dit, à ma grande surprise, il a semblé courir assez vite - j'ai couru la méthode posthelper.page() 100 fois et cela a pris environ 0.5 secondes.

Je ne voulais pas publier cela dans la question réelle, donc il ne serait pas influencer les réponses autant - voici le code:

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

Le CouchDB HTTP View API donne beaucoup de possibilités de faire la pagination efficace .

La méthode la plus simple utiliserait startkey et count. Count est le nombre maximum d'entrées que CouchDB retournera pour cette demande d'affichage, quelque chose qui dépend de votre conception, et startkey est l'endroit où vous voulez que CouchDB démarre. Lorsque vous demandez l'affichage, il vous indique également le nombre d'entrées disponibles, ce qui vous permet de calculer le nombre de pages que vous souhaitez afficher si vous le souhaitez.

Ainsi, la première requête ne spécifierait pas une clé de démarrage, mais seulement le nombre d'entrées que vous voulez afficher. Vous pouvez ensuite noter la clé de la dernière entrée renvoyée et l'utiliser comme clé de démarrage pour la page suivante. Dans cette forme simple, vous obtiendrez un chevauchement, où la dernière entrée d'une page est la première de la suivante. Si cela n'est pas souhaitable, il est trivial de ne pas afficher la dernière entrée de la page.

Une méthode plus simple consiste à utiliser le paramètre skip pour élaborer le document de départ de la page, mais cette méthode doit être utilisée avec précaution. Le paramètre skip fait simplement que le moteur interne ne renvoie pas les entrées qu'il parcourt. Bien que cela donne le comportement souhaité, il est beaucoup plus lent que de trouver le premier document pour la page par clé. Plus les documents ignorés sont longs, plus la demande sera lente.

+0

Aha! De cette page vous avez lié: le paramètre count peut être combiné avec le "skip = nombre de lignes à sauter". Parfait. – dbr

+0

J'ai ajouté les informations ci-dessus à votre réponse (pour ma référence si rien d'autre), j'espère que cela ne vous dérange pas! – dbr

+2

Je l'ai édité encore. Utiliser skip n'est pas un bon moyen de le faire dans la plupart des cas. – Kerr