xaxa
xaxa

Reputation: 1159

Mongoid dynamic query

This must be an easy one, but I'm stuck... So I'm using Rails#3 with Mongoid and want to dynamically build query that would depend upon passed parameters and then execute find(). Something like

def select_posts
    query = :all # pseudo-code here
    if (params.has_key?(:author))
        query += where(:author => params[:author]) # this is pseudo-code again
    end

    if (params.has_key?(:post_date))
        query += where(:create_date => params[:post_date]) # stay with me
    end

    @post_bodies = []
    Post.find(query).each do |post| # last one
        @post_bodies << post.body
    end

    respond_to do |format|
        format.html
        format.json { render :json => @post_bodies }
    end
end

Upvotes: 2

Views: 1328

Answers (1)

theTRON
theTRON

Reputation: 9659

You have a few different options to go with here - depending on how complex your actual application is going to get. Using your example directly - you could end up with something like:

query = Post.all
query = query.where(:author => params[:author]) if params.has_key?(:author)
query = query.where(:create_date => params[:post_date]) if params.has_key?(:post_date)
@post_bodies = query.map{|post| post.body}

Which works because queries (Criteria) in Mongoid are chainable.


Alternatively, if you're going to have lots more fields that you wish to leverage, you could do the following:

query = Post.all
fields = {:author => :author, :post_date => :create_date}
fields.each do |params_field, model_field|
  query = query.where(model_field => params[params_field]) if params.has_key?(params_field)
end
@post_bodies = query.map{|post| post.body}

And finally, you can take it one level further and properly nest your form parameters, and name the parameters so that they match with your model, so that your params object looks something like this:

params[:post] = {:author => "John Smith", :create_date => "1/1/1970", :another_field => "Lorem ipsum"}

Then you could just do:

@post_bodies = Post.where(params[:post]).map{|post| post.body}

Of course, with that final example, you'd want to sanitize the input fields - to prevent malicious users from tampering with the behaviour.

Upvotes: 5

Related Questions