Rails计算链接表

时间:2015-06-23 14:54:42

标签: ruby-on-rails activerecord

我有三个相互链接的对象。它看起来像这样:

tree[
  id: 1,
  name: "name"
]

branch[
  id: 1,
  tree_id: 1
]

leaf[
  id: 1,
  branch_id:1
]

我需要知道每棵树有多少叶子,所以我创建了一个嵌套的for循环:

更新

我更新了代码:

results = []
trees = Tree.all
trees.each do |tree|
  branches = Branch.where(tree_id: tree.id)
  branches.each do |branch|
   leaves_count = leaves.where(branch_id: branch.id).count
  end
  results.push( {
    tree: tree.name,
    leaves: leaves_count
  })
end

使用此代码我收到一组对象:

results = [{  
    tree: "oak",
    leaves: 4
  }, {
    tree: "redwood",
    leaves: 6
}]

我想要相同的输出,但是以轨道方式

这有效,但感觉真的很笨重。有没有人知道修复此问题的方法?

更新已解决

Yury Lebedev的答案是正确的,但通过他之前的回答,我发现了另一种方式。所以这有效(尤里的答案):

Tree.find_each do |tree|
  Branch.where(tree_id: tree.id).joins(:leaves).count('leaves.id')
end

这也有效:

Tree.find_each do |tree|
  Tree.joins(branches: :leaves).where(id: tree.id).count('leaves.id')
end

作为一个延续问题(不确定我是否应该在回答的问题上这样做?)我想知道我有一个比另一个更好/更快,或者他们是否相同。< / p>

1 个答案:

答案 0 :(得分:2)

您可以尝试使用连接查询(这只会对数据库进行一次查询):

Leaf.joins('inner join branches on leaves.branch_id = branches.id')
  .group('branches.tree_id').count

这将为您提供一个以tree_id为键的哈希值,并将计数保留为值。

如果你想遍历树,并获得每个树的叶数,你可以这样做(如果你有n棵树,这将对数据库进行n次查询):

trees.each do |tree|
  leaves_count = Branch.where(tree_id: tree.id).joins('inner join leaves on leaves.branch_id = branches.id')
    .count('leaves.id')
end

如果您的模型中有关联,那么这可以更容易地完成:

class Three < ActiveRecord::Base
  has_many :branches
  has_many :trees, through: :branches
end

class Branch < ActiveRecord::Base
  belongs_to :tree
  has_many :leaves
end

class Leaf < ActiveRecord::Base
  belongs_to :branch
  delegate :tree, to: :branch
end

然后是一个查询:

Leaf.joins(:branch).group('branches.tree_id').count

And for a query for each tree:

Tree.find_each do |tree|
  Branch.where(tree_id: tree.id).joins(:leaves).count('leaves.id')
end