Reputation: 1325
I have a Gift
model:
class Gift
include Mongoid::Document
include Mongoid::Timestamps
has_many :gift_units, :inverse_of => :gift
end
And I have a GiftUnit
model:
class GiftUnit
include Mongoid::Document
include Mongoid::Timestamps
belongs_to :gift, :inverse_of => :gift_units
end
Some of my gifts have gift_units, but others have not. How do I query for all the gifts where gift.gift_units.size > 0
?
Fyi: Gift.where(:gift_units.exists => true)
does not return anything.
Upvotes: 2
Views: 2046
Reputation: 809
I tried to find a solution for this problem several times already and always gave up. I just got an idea how this can be easily mimicked. It might not be a very scalable way, but it works for limited object counts. The key to this is a sentence from this documentation where it says:
Class methods on models that return criteria objects are also treated like scopes, and can be chained as well.
So, get this done, you can define a class function like so:
def self.with_units
ids = Gift.all.select{|g| g.gift_units.count > 0}.map(&:id)
Gift.where(:id.in => ids)
end
The advantage is, that you can do all kinds of queries on the associated (GiftUnits) model and return those Gift instances, where those queries are satisfied (which was the case for me) and most importantly you can chain further queries like so:
Gift.with_units.where(:some_field => some_value)
Upvotes: 1
Reputation: 434945
That has_many
is an assertion about the structure of GiftUnit
, not the structure of Gift
. When you say something like this:
class A
has_many :bs
end
you are saying that instance of B
have an a_id
field whose values are id
s for A
instances, i.e. for any b
which is an instance of B
, you can say A.find(b.a_id)
and get an instance of A
back.
MongoDB doesn't support JOINs so anything in a Gift.where
has to be a Gift
field. But your Gift
s have no gift_units
field so Gift.where(:gift_units.exists => true)
will never give you anything.
You could probably use aggregation through GiftUnit
to find what you're looking for but a counter cache on your belongs_to
relation should work better. If you had this:
belongs_to :gift, :inverse_of => :gift_units, :counter_cache => true
then you would get a gift_units_count
field in your Gift
s and you could:
Gift.where(:gift_units_count.gt => 0)
to find what you're looking for. You might have to add the gift_units_count
field to Gift
yourself, I'm finding conflicting information about this but I'm told (by a reliable source) in the comments that Mongoid4 creates the field itself.
If you're adding the counter cache to existing documents then you'll have to use update_counters
to initialize them before you can query on them.
Upvotes: 3