Rails 4 and mongoid: programmatically build a quer

2019-09-05 01:06发布

问题:

I want to be able to dynamically transform an input hash like the following:

{ name: ['John', 'Luke'], status: ['ACTIVE', 'SUSPENDED'] }

in a query that will put the different fields (name, status) in a AND relationship, and the values for each field in a OR relationship. In SQL that would be something like this:

SELECT * 
FROM my_class 
WHERE (name LIKE 'John' OR name LIKE 'Luke') 
AND (status LIKE 'ACTIVE' OR status LIKE 'SUSPENDED')

I've tried different approaches but I'm kind of stucked. Here what works for one field with multiple values:

def search(criteria)
    result = MyClass.all

    criteria.each do |field, values|
      values = [values] unless values.respond_to?(:each)

      conditions = []
      values.each do |v|
        conditions << { field => v } unless v.empty?
      end

      result = result.or(conditions) # this is enough for one field only, but how to create an AND condition with the second field (and so on)?
    end

    result
  end

I've read about any_of but it's not completely clear to me how to use it.

回答1:

The query you want to build is:

MyClass.where(
  :name.in   => [ 'John', 'Luke' ],
  :status.in => [ 'ACTIVE', 'SUSPENDED' ]
)

A :field.in works the same as field in (...) in SQL and that's just a short form for an or-statement. That makes things quite a bit easier as you just have to add .in calls to the criteria keys whose vales are arrays, something like this:

query = criteria.each_with_object({}) do |(field, values), query|
  field = field.in if(values.is_a?(Array))
  query[field] = values
end
MyClass.where(query)