2

Let's assume I have a grandparent document with many parents, and each parent has many children.

What is the best way, in Rails with Mongoid, to get all of the children for a specific grandparent without looping?

For example, if I were to use loops, it would look something like this (rough code):

  def children
    children = []
    parents.each do |p|
      p.children.each do |c|
        children << c
      end
    end
    children.uniq
  end

class Grandparent
  include Mongoid::Document
  has_many :parents
end

class Parent
  include Mongoid::Document
  belongs_to :grandparent
  has_many :children
end

class Child
  include Mongoid::Document
  belongs_to :parent
end
Baub
  • 5,004
  • 14
  • 56
  • 99

1 Answers1

0

A method like this, it would load the children as an attribute once called.

def children(reload=false)
   @children = nil if reload
   @children ||= Child.where(:parent_id.in =>  parents.map(&:id))
end

See this SO answer as well

Community
  • 1
  • 1
tihom
  • 7,923
  • 1
  • 25
  • 29
  • This returns nil: `children = Child.where(:parent_id.in => parents.map(&:id))`, but the looping example in my question works. – Baub Sep 23 '13 at 03:13
  • @James it would help if you post the model files showing how the associations are defined. – tihom Sep 23 '13 at 03:27
  • @tihorn added to the original question. – Baub Sep 23 '13 at 03:33
  • @James give it another try, changed from `:id` to `:_id` in `map`. Also added a reference question with similar answer. – tihom Sep 23 '13 at 03:46
  • @tihorn, I am so embarrassed. I was testing this with `rspec` and my factories were being built but not created. Since they weren't in the database, calling `Child.where` would return `nil` because, well, none of the `children` had been saved. – Baub Sep 23 '13 at 04:33
  • So to be clear, this is what worked: `Child.where(:parent_id.in => parents.map(&:id))` – Baub Sep 23 '13 at 04:34
  • It should work according to the answer you linked. I am finding that this is profiling quite slow, though. `| #children | 55.766 ms | 683.727 ms | 369.746 ms | 739.493 ms | 2` where 55 is the min, 683 is the max, and 369 is the average. – Baub Sep 23 '13 at 05:11
  • to speed it up you can add an index on child table for parent_id – tihom Sep 23 '13 at 05:13