Mongoid で or 条件を組むには any_of を使う。

Model.any_of({:label => /foo/}, {:name => /foo/})
=> #<Mongoid::Criteria
  selector: {"$or"=>[{"label"=>/foo/}, {"name"=>/foo/}]}
  options:  {}
  class:    Model
  embedded: false>

Mongoid で and 条件を組むには all_of を使う。

Model.all_of({:label => /foo/}, {:name => /foo/})
=> #<Mongoid::Criteria
  selector: {"$and"=>[{"label"=>/foo/}, {"name"=>/foo/}]}
  options:  {}
  class:    Model
  embedded: false>

では、(A or B) and (C or D) のような、or 条件の and 条件(またはその逆)はどのように組めば良いか? any_of や all_of ではサポートされていないようだ。

実は、直接 Mongoid::Criteria を作って組み立てるという裏技で実現することができる。Criteria#selector はただのハッシュなので自分で簡単に組み立てられるのだ。

criteria = Mongoid::Criteria.new(Model)
or_selector1
= {"$or"=>[{"label"=>/foo/}, {"name"=>/foo/}]} or_selector2 = {"$or"=>[{"label"=>/bar/}, {"name"=>/bar/}]} and_selector = {"$and"=>[or_selector1, or_selector2]} criteria.selector = and_selector

criteria
=> #<Mongoid::Criteria selector: {"deleted_at"=>nil, "$and"=>[ {"$or"=>[{"label"=>/foo/}, {"name"=>/foo/}]}, {"$or"=>[{"label"=>/bar/}, {"name"=>/bar/}]} ]} options: {} class: Model embedded: false>

あとは criteria.first とかするとクエリが投げられて結果が返ってくる。便利。