Items
通过parent_id
属性组织在文件夹/树状结构中。因此可以创建以下层次结构:
问题是 - 我想不出一种优雅的方法来检索Item
的所有子项目树。一种解决方案是使用递归。
我的递归解决方案(recursive_subitems
方法)目前无效。但即使它会起作用 - 我还有兴趣,如果还有其他的递归替代方案吗?也许一些棘手的SQL查询?
# == Schema Information
#
# Table name: items
#
# id :integer not null, primary key
# name :string
# parent_id :integer
class Item < ActiveRecord::Base
# for item with ID 1 must return items with IDs [2, 3]
def immediate_subitems
Item.where(parent_id: self.id)
end
# My failing attempt to create a recursive function...
def recursive_subitems(parent_id)
items_ids = Item.where(parent_id: parent_id).map(&:id)
items_ids.each do |item_id|
recursive_subitems(item_id)
end
items_ids
end
# for item with ID 1 must return items
# with IDs [2,3,4,5,6,7,8,9,10,11]
def all_subitems_tree
recursive_subitems(self.id)
end
end
答案 0 :(得分:1)
这里的工作递归方法:
def recursive_subitems(parent_id)
# byebug
result = []
items_ids = Item.where(parent_id: parent_id).map(&:id)
return [parent_id] if items_ids.empty?
items_ids.each do |item_id|
result << recursive_subitems(item_id)
end
result << parent_id
end
def all_subitems_tree
puts "subitems tree for #{self.id}"
ids = recursive_subitems(self.id).flatten
ids.pop
Item.find(ids)
end
答案 1 :(得分:0)
有一个名为ActsAsTree的简单宝石。 它是过去Rails的一部分
它有一些简化器,包括方法.walk_tree
,它可以执行@yaru proposed
答案 2 :(得分:0)
在RDMS中有两种主要模式可以有效地表示树结构:物化路径和嵌套集。
https://github.com/stefankroes/ancestry和https://github.com/ClosureTree/closure_tree都实现了物化路径,尽管有所不同。阅读这篇关于它们相对优点的文章 - https://www.hilman.io/blog/2015/09/comparing-ancestry-and-closure_tree/
https://github.com/collectiveidea/awesome_nested_set实现了嵌套集模式。
物化路径模式的基本思想是每个元素还包括从根节点到自身的完整路径。 Ancestry通过添加包含此路径的文本ancestry
列来完成此操作:10/34/78/...
。找到节点的所有子节点然后简化为一个简单而有效的索引前缀字符串搜索(where ancestry like 'id1/id2/%
)。
Closure Tree将它保存在一个单独的表中,但也使这种搜索非常有效。
嵌套集的基本思想是除了parent_id
之外,它还有left
和right
个边界,其值保持不变,以便所有子ID都在它们之间。在这种情况下,找到它们变得简单where id between left and right
。
所有这三种实现都允许您在大多数读操作中减少n + 1。写操作(添加,更改,删除,移动节点)具有不同的成本,因此如果您计划经常更新树,请务必检查它们。