Search code examples
ruby-on-railsmongodbruby-on-rails-4mongoidmongoid4

Mongoid: Query for objects where has_many associations have certain field values


I have a GiftCategory model:

class GiftCategory
  include Mongoid::Document

  field :gifts_count, type: Integer
  has_many :gifts, :inverse_of => :gift_category
end

And I have a Gift model:

class Gift
  include Mongoid::Document

  field :gift_units_count, type: Integer
  has_many :gift_units,      :inverse_of => :gift
  belongs_to :gift_category, :inverse_of => :gifts, :counter_cache => true

  after_save :update_counter

  def update_counter
    self.gift_category_id_change.each do |e|
      GiftCategory.reset_counters(e, :gifts) unless e.nil?
    end
  end
end

The update_countermethod allows me keep count of how many Gift objects belongs a GiftCategory. This way I can e.g. query only for GiftCategory objects that have some Gift objects:

GiftCategory.where(:gifts_count.gt => 0)

But as you can see, a Gift has a gift_units_count field as well. This field keeps count of the number units available of the Gift. How can I query for GiftCategory objects that has Gift objects with gift_units_count > 0?

I think that a solution could be something like described here, but I can't get closer myself.


Solution

  • That isn't inherently possible, since the document is referenced.

    It's important to remember that GiftCategory doesn't actually contain a Gift. Instead, the Gift records have a field called gift_category_id. You essentially would need to find Gift records which have a gifts_unit_count > 0, then compile a list of their gift_category_id fields, unique them, and then retrieve those records.

    This would do roughly what I've stated above:

    gift_category_ids = Gift.where(:gifts_unit_count.gt => 0).map {|g| g.gift_category_id}.uniq
    for gift_category_id in gift_category_ids
      gift_category = GiftCategory.find(gift_category_id)
      # do something with this
    end
    

    As far as I know, Mongoid is not willing to do something like this for you. As someone commented above, you may want to consider embedding, which would allow you to query this way, since the fields will be stored in the same document.