Mongoid: query based on the size of the inline array of documents

This is similar to this question, but I cannot figure out how to convert it to Mongoid syntax:

MongoDB query based on the number of embedded documents

Say I have Customer: {_id: ..., orders: [...]}

I want to find all customers who have existing orders, i.e. orders.size> 0. I tried requests like Customer.where(:orders.size.gt => 0) no avail. Can this be done using the exists? operator exists? ?

+5
source share
2 answers

It’s best to use your own MongoDB syntax rather than using rails similar to JavaScript methods or evaluation, as indicated in the accepted answer to the question you are referring to. Especially since evaluating JavaScript conditions will be much slower.

The logical extension $exists for an array with some length greater than zero is to use "dot notation" and check for the presence of a "zero index" or the first element of the array:

 Customer.collection.find({ "orders.0" => { "$exists" => true } }) 

This can be done with any index value, where n-1 is equal to the index value for the "length" of the array that you are testing at least.

It is worth noting that to exclude an array of "zero length", the $size operator is also a valid alternative when used with $not to cancel the match:

 Customer.collection.find({ "orders" => { "$not" => { "$size" => 0 } } }) 

But this is not very suitable for larger "dimensional" tests, since you will need to specify all sizes that need to be excluded:

 Customer.collection.find({ "$and" => [ { "orders" => { "$not" => { "$size" => 4 } } }, { "orders" => { "$not" => { "$size" => 3 } } }, { "orders" => { "$not" => { "$size" => 2 } } }, { "orders" => { "$not" => { "$size" => 1 } } }, { "orders" => { "$not" => { "$size" => 0 } } } ] }) 

So the other syntax is clearer:

 Customer.collection.find({ "orders.4" => { "$exists" => true } }) 

This means 5 or more members are compressed.

Also note that none of these conditions can only contain an index, so if you have another filtering point, it is best to include this condition.

+7
source

Just adding my solution, which might be useful for someone:

 scope :with_orders, -> { where(orders: {"$exists" => true}, :orders.not => {"$size" => 0}}) } 
+5
source

Source: https://habr.com/ru/post/1201287/


All Articles