Pagination with kaminari broken when using custom view map #126

Closed
raldred opened this Issue Nov 4, 2011 · 4 comments

Comments

Projects
None yet
2 participants

raldred commented Nov 4, 2011

I am experiencing issues with pagination when using a custom view

 ExamSitting Model

design do
  view :by_exam_updated_at_and_completed,
     :map => 
       "function(doc) {
         if ((doc['couchrest-type'] == 'ExamSitting') && (doc['score'] != null) && (doc['updated_at'] != null) && (doc['exam_id'] != null) && (doc['preview'] != true)) {
           emit([doc['exam_id'], doc['updated_at']], null);
         }
       }"
end

 controller

@per_page = 10    
@page = params[:page]
@exam_sittings = ExamSitting.by_exam_updated_at_and_completed.startkey([@exam.id, 0]).endkey([@exam.id, 'Z']).descending.page(@page).per(@per_page)

view

paginate @exam_sittings

the helper prints 2 pages, when there is only 1 result.
although looking deeper into couch, it appears the total_count method is returning the wrong number of results.
Possibly something to do with lazy loading?

@raldred raldred added a commit to raldred/couchrest_model that referenced this issue Nov 8, 2011

@raldred raldred Test to prove View#count returns the wrong value
when using a compound key range.
This then causes incorrect values from #num_pages for pagination.

couchrest#126 #126
70a8336

raldred commented Nov 8, 2011

Please see my commit [70a8336] tests confirming the issue.

@raldred raldred added a commit to raldred/couchrest_model that referenced this issue Nov 8, 2011

@raldred raldred pagination total_count to use #length of result set
fixes #126 View#num_pages retuning incorrect values with range queries
9ece48b

raldred closed this Nov 8, 2011

raldred commented Nov 8, 2011

see pull request #127

Owner

samlown commented Feb 29, 2012

Hi!

Following on from my comment on #127. The problem here is that there is no guaranteed why to grab the total number of documents returned by the view. Using the length method will work, but you may as well just remove pagination as you'll still end up loading all the documents in the search.

You've a couple of options:

  1. Use "infinity scrolling". Works best with Javascript/AJAX. Instead of trying to number and paginate the results, just stick a "view more" button to the end of the result set and use CouchDBs standard limit and skip requests. They say even this can run into problems if you have to skip lots of documents, but its probably not worth worrying about unless you're into millions of documents, which you are very unlikely to skip! (hope that makes sense!)
  2. If you insist on using pagination, use the reduce method to calculate a count or sum of the total number of documents in the query. Here's your original view with the reduce function:
design do
  view :by_exam_updated_at_and_completed,
     :map => 
       "function(doc) {
         if ((doc['couchrest-type'] == 'ExamSitting') && (doc['score'] != null) && (doc['updated_at'] != null) && (doc['exam_id'] != null) && (doc['preview'] != true)) {
           emit([doc['exam_id'], doc['updated_at']], 1);
         }
       }", :reduce => "function(k,v,r) { return sum(v); }"
end

You'll notice the emit now has a 1, and the reduce function will calculate the sum. The couchrest_model views are designed to handle this type of view automatically so that pagination just works. Indeed, the count method, instead of using the total_rows provided by CouchDB, will perform a reduced query to get the sum of page counts.

Hope that helps!
Cheers,
sam

raldred commented Mar 1, 2012

Hi Sam,
Thanks for looking into this.

Personally I'm not insisting on pagination, I'd much prefer a modern approach, however, the app is for universities and one of the requirements is that it must work for screen readers and those without javascript, therefore a traditional approach to pagination is really the only option when you have thousands of documents.

I will test the example reduce map, let you know how I get on.

Thanks
--Rob

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment