Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Question regarding chaining multiple any_of criteria #Mongoid

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?

like image 954
Rakeesh Avatar asked Jan 19 '11 09:01

Rakeesh


3 Answers

You can do it with avoid any_of.

criteria = Collection.where('$or' => [{"field1" => "value1"}, {"field2" => "value2"}])
criteria = criteria.where('$or' => [{"field3" => "value3"}, {"field4" => "value4"}])
like image 189
shingara Avatar answered Nov 14 '22 12:11

shingara


you can write this with mongoid 2.4.0:

  Collection.all_of({"$or" => [{"field1" => "value1"}, {"field2" => "value2"}]}, {"$or" => [{"field3" => "value3"}, {"field4" => "value4"}]})
like image 4
TlmaK0 Avatar answered Nov 14 '22 13:11

TlmaK0


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.

like image 2
Martin Westin Avatar answered Nov 14 '22 12:11

Martin Westin