我有一个Business
模型:belongs_toCategory
类别的示例层次结构:
- 根
- 餐厅
- 寿司
- 比萨
- 中国人
- 法语
- 意大利语
- 餐厅
我正在使用acts_as_tree
层次Category
结构。
如何Businesses
在餐厅类别下找到所有内容?
我有一个Business
模型:belongs_toCategory
类别的示例层次结构:
我正在使用acts_as_tree
层次Category
结构。
如何Businesses
在餐厅类别下找到所有内容?
如果您想在树状层次结构中获取节点的所有后代,您有两种选择:
使用经典acts_as_tree
,预加载所选类别,启动级联查询以检索所有子代、孙代等,直到您只获得叶子(没有更多子代的节点)。这种方法和听起来一样好。
使用更高级的树表示,例如嵌套集或闭包树。在这些表示下,您只需一个查询即可获得特定节点的所有后代。
然后在Businesses中获取收集的类别和查询:
Business.where(:category => categories)
(技术解释:嵌套集)
在嵌套集表示下,每个节点都有两个索引,分配方式如下:想象每个节点是一个有两个窗户的房子,东和西,树就像一条分叉的道路,所有孩子或多或少都到他们父母的北边。所以你从根房子的东边开始,在你遇到的窗户上放一个序号。你从不穿过任何马路,你只被允许绕过没有进一步通往北方的道路的房屋。最后你会再次回到根屋,并在西窗上放一个号码。
分配的数字将具有以下属性:
因此,虽然在树中插入一个新元素的成本很高(它需要更新许多索引),但检索整个后代(所有子代、孙代......)非常容易,只需选取“东”和“西”数字介于您选择的类别的东和西之间。您实际上可以做得更好,但这并不重要。
像https://github.com/collectiveidea/awesome_nested_set这样的库将为您管理所有这些,您只需调用
categories = @category.self_and_descendants.to_a
(技术解释:闭包树)
这种方法需要一个附件表,您可以在其中存储child->parent
关系的传递闭包(请参阅http://en.wikipedia.org/wiki/Reflexive_transitive_closure#P_closures_of_binary_relations)
该表将包含所有祖先-后代对,因此您可以以智能方式加入该表以获得几乎任何层次结构的切片。
同样,像https://github.com/mceachen/closure_tree这样的库将为您完成艰苦的工作,您将能够做到
categories = @category.self_and_descendants.to_a
你能不能只做这样的事情:
Category.find_by_name("Restaurants").businesses
编辑:
没有意识到您也想要餐厅子类别中的企业,呵呵。
对于多个层次结构,您首先需要获取所有类别,然后遍历每个类别,找到业务,然后将它们连接在一起
class Company < ActiveRecord::Base
...
def all_children
all = []
self.children.each do |c|
all << c
root_cs = c.all_children.flatten
all << root_cs unless root_cs.empty?
end
return all.flatten
end
end
然后你可以打电话:
root_category = Category.find_by_name("Restaurants")
categories = root_category.all_children
businesses = categories.map{ |c| c.businesses }.flatten
这应该会返回您的企业列表。虽然看起来不太好,但我觉得应该有一个更优化的方法。
希望无论如何它应该给你一些思考的食物。
category = Category.find_by_name("Restaurants")
那么对于业务
category.business
如果你想要孩子喜欢(寿司、比萨、中餐……)那么
category.childrens
要查找所有类别,请在 category.rb 中添加以下方法
def all_children
all = []
self.children.each do |category|
all << category
root_children = category.all_children.flatten
all << root_children unless root_children.empty?
end
return all.flatten
end
然后使用
@category.all_children
已编辑 查找餐厅类别和餐厅所有子类别的企业。
Business.where("category_id = ? OR category_id in (?)", category.id, category.all_children.map(&:id))