ruby-on-railsmongoid

Getting the last document of limited Mongoid query result and .count()


I'm using Mongoid to work with MongoDB. Everything is fine, I like it very much and so on. In my blog application (posts controller, index action) I have this code:

@posts = Post.without(:comments)
@posts = @posts.my_search(params[:s]) if params[:s]
@posts = @posts.order_by([:created_at, :desc])
@posts = @posts.where(:pid.lt => params[:p].to_i+1) if params[:p]
@posts = @posts.limit(items_per_page+1)

The part with "where" is implementation of my own pagination method (allows to page results in one direction only, but without skip(), what I consider a plus). Now, there are few small problems that make me feel uncomfortable:

For my pagination to work I need to get the last post within that limit. But when I do @posts.last I'm getting last document of the whole query without limit. Ok, this is strange, but not a big problem. Other than that, query results act like almost-ordinary-array, so at this moment I'm getting the last element with @posts.pop (funny, but it doesn't remove any documents) or @posts.fetch(-1)

I have a feeling that this isn't "right way" and there mush be something more elegant. Also @posts.count generates second query exactly the same as first one (without limit) but with "count" only and I don't like it.

If I make the last line look like

@posts = @posts.limit(items_per_page+1).to_ary

to convert query results into array, everything generates only one query (good), but now @posts.count stops reporting what I need (total amount of documents without limit applied) and behaves exactly like @posts.size - it returns items_per_page+1 or less (bad).

So, here are my questions:

  1. What is a "correct" way to get the last document of query results within given limit?
  2. How to get total amount of documents with given conditions applied without generating additional query?
  3. @posts.first generates additional query, how to prevent it and just get first document before I iterate all documents?

Solution

  • Getting the last document:

    Post.last 
    

    Getting last document with some other queries:

    Post.order_by([:created_at, :desc]).last
    

    Getting total number documents:

    Post.order_by([:created_at, :desc]).count
    

    Recommendation: Just use the built in pagination

    @posts = Post.limit(10).paginate(:page=>pararms[:page])
    

    later:

    <%= will_paginate @posts %>
    

    Regarding the additional queries -- mongoid lazy loads everything:

    @posts = Post.all #no query has been run yet
    @posts.first #Ok, a query has finally been run because you are accessing the objects