Paginazione in CouchDB?

Come andrei sull’implementazione delle query richieste per l’impaginazione?

Fondamentalmente, quando viene richiesta la pagina 1, ottieni le prime 5 voci. Per la pagina 2, prendi i prossimi 5 e così via.

Ho intenzione di usarlo tramite il modulo couchdb-python, ma questo non dovrebbe fare alcuna differenza per l’implementazione.

La Guida CouchDB ha una buona discussione sull’impaginazione, incluso un sacco di codice di esempio, qui: http://guide.couchdb.org/draft/recipes.html#pagination Ecco il loro algoritmo:

  • Richiedi rows_per_page + 1 righe dalla vista
  • Visualizza righe rows_per_page , memorizza l’ultima riga come next_startkey
  • Come informazioni sulla pagina, mantieni startkey e next_startkey
  • Utilizza i valori next_* per creare il link successivo e usa gli altri per creare il link precedente

NB: il modo corretto per recuperare le pagine in CouchDB è specificando una chiave iniziale, non un indice iniziale come potresti pensare. Ma come fai a sapere quale chiave per iniziare la seconda pagina? La soluzione intelligente: “Invece di richiedere 10 righe per una pagina, richiedi 11 righe, ma ne visualizzi solo 10 e utilizzi i valori dell’11a riga come startkey per la pagina successiva.”

Se si prevede che più documenti emettano chiavi identiche, sarà necessario utilizzare startdocid oltre a startkey per impaginare correttamente. Il motivo è che startkey da solo non sarà più sufficiente per identificare in modo univoco una riga. Questi parametri sono inutili se non si fornisce una startkey . In effetti, CouchDB prima guarderà il parametro startkey , quindi userà il parametro startdocid per ridefinire ulteriormente l’inizio dell’intervallo se più potenziali righe staring hanno la stessa chiave ma ID di documento diversi. La stessa cosa per il enddocid .

L’API di visualizzazione HTTP CouchDB offre un sacco di possibilità per eseguire il paging in modo efficiente.

Il metodo più semplice userebbe startkey e count . Conta è il numero massimo di voci che CouchDB restituirà per quella richiesta di visualizzazione, qualcosa che dipende dal tuo progetto, e startkey è dove vuoi che CouchDB inizi. Quando richiedi la vista, ti dirà anche quante voci ci sono, permettendoti di calcolare quante pagine ci saranno se vuoi mostrarlo agli utenti.

Quindi la prima richiesta non specificherà una startkey, solo il conteggio per il numero di voci che vuoi mostrare. È quindi ansible prendere nota della chiave dell’ultima voce restituita e utilizzarla come chiave di avvio per la pagina successiva. In questo semplice modulo, si otterrà una sovrapposizione, in cui l’ultima voce di una pagina è la prima di quella successiva. Se questo non è desiderabile è banale semplicemente non mostrare l’ultima voce della pagina.

Un metodo più semplice per farlo consiste nell’usare il parametro skip per elaborare il documento iniziale per la pagina, tuttavia questo metodo dovrebbe essere usato con caucanvas. Il parametro skip fa semplicemente in modo che il motore interno non restituisca voci su cui sta iterando. Mentre questo dà il comportamento desiderato è molto più lento di trovare il primo documento per la pagina per chiave. Più documenti vengono saltati, più lenta sarà la richiesta.

Questo è quello che ho inventato finora – per ottenere gli ID di tutti i post, quindi recuperare gli elementi effettivi per il primo x numero di ID ..

Non è terribilmente efficiente, ma molto più che recuperare tutti i post, quindi buttare via la maggior parte del gioco. Detto questo, con mia sorpresa, è sembrato funzionare abbastanza rapidamente – ho eseguito il metodo posthelper.page() 100 volte e ci sono voluti circa 0,5 secondi.

Non volevo postare questo nella domanda reale, quindi non influenzerebbe le risposte tanto – ecco il codice:

 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