I have a requirement where I need to run a MongoDB query like the following:
db.collection.find({ $or : [{"field1" : "value1"}, {"field2" : "value2"}], $or : [{"field3" : "value3"}, {"field4" : "value4"}]})
i.e.
(field1 == value 1 or field2 == value2) and (field3 == value3 or field4 == value4)
I want to achieve this through criteria chaining because the query gets formed dynamically from different parts of the code. But if I try doing something like the following
criteria = Collection.any_of({"field1" => "value1"}, {"field2" => "value2"}) criteria = criteria.any_of({"field3" => "value3"}, {"field4" => "value4"})
I get the resultant query where all these are combined into a single $or statement like
db.collection.find({ $or : [{"field1" : "value1"}, {"field2" : "value2"}, {"field3" : "value3"}, {"field4" : "value4"}]})
What is the way to achieve "and" of the two "any_of" using criteria chaining?
You can do it with avoid any_of.
criteria = Collection.where('$or' => [{"field1" => "value1"}, {"field2" => "value2"}])
criteria = criteria.where('$or' => [{"field3" => "value3"}, {"field4" => "value4"}])
you can write this with mongoid 2.4.0:
Collection.all_of({"$or" => [{"field1" => "value1"}, {"field2" => "value2"}]}, {"$or" => [{"field3" => "value3"}, {"field4" => "value4"}]})
For Mongoid 3 and 4 there is a relatively nice way of chaining or criteria without merging.
TL;DR
MyModel.all_of(MyModel.xxx.selector, MyModel.yyy.selector)
Mongoid maintainer Durran showed the above trick in this Github issue: https://github.com/mongoid/mongoid/issues/2170
You can arbitrarily chain criteria using the same technique and some array trickery like this:
selectors = []
selectors << MyModel.search(term) if term
selectors << MyModel.some_any_of if some_condition
selectors << MyModel.some_other_any_of if some_other_condition
...
MyMode..all_of(*selectors)
Each row will add another and condition.
It may be worth noting too that you do not have to build each selector from the model. You can get an initial scope back from your permission system or something ans just call .selector on it before adding on more criteria.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With