【发布时间】:2020-07-05 14:07:37
【问题描述】:
我有一个带有自引用对象的树状活动记录结构 - 例如,该对象可以是同一类的另一个对象的父级或子级。我需要一种在代码中有效映射此结构的方法。到目前为止,我一直在使用活动记录 ORM 使用 ruby 进行此操作,但效率非常低。
这是 pod.rb 模型的样子:
has_many :pod_parents, class_name: "PodPod", dependent: :delete_all
has_many :parents, through: :pod_parents, :foreign_key => 'parent_id', :source => 'parent'
has_many :pod_children, class_name: "PodPod", :foreign_key => 'parent_id'
has_many :children, through: :pod_children, :source => 'pod'
scope :active, -> {
where(pod_state: "active").where(pod_type: ["standard","readonly"])
}
这是相关的数据库架构:
table "pods"
t.string "intention"
t.integer "user_id"
t.string "slug"
t.string "url_handle"
t.index ["slug"], name: "index_pods_on_slug"
t.index ["url_handle"], name: "index_pods_on_url_handle"
table "pod_pods"
t.integer "parent_id"
t.integer "pod_id"
t.index ["parent_id", "pod_id"], name: "index_pod_pods_on_parent_id_and_pod_id", unique: true
t.index ["parent_id"], name: "index_pod_pods_on_parent_id"
t.index ["pod_id"], name: "index_pod_pods_on_pod_id"
以下是我正在优化的具体功能:
def get_all_parents
parents = []
self.parents.active.each do |parent|
parents << parent
parents.concat(parent.get_all_parents)
end
return parents
end
def get_all_children
children = []
self.children.each do |child|
children.concat(child.get_all_children)
end
return children
end
def get_all_parents_and_children
pod_array = self.get_all_parents
pod_array.concat(self.get_all_children)
return pod_array
end
def get_all_relations(inclusive = false)
circles_array = self.get_all_parents
circles_array.each do |parent|
circles_array = circles_array.concat(parent.get_all_children)
end
circles_array = circles_array.concat(self.get_all_children)
unique_ids = circles_array.compact.map(&:id).uniq - [self.id]
circles = Pod.where(id: unique_ids)
end
据我所知,Postgres 支持一种递归 SQL 查询。我一直在用这些文章来指路:1、2。
这是据我所知:
def get_all_parents2
sql =
<<-SQL
WITH RECURSIVE pod_tree(id, path) AS (
SELECT id, ARRAY[id]
FROM pods
WHERE id = #{self.id}
UNION ALL
SELECT pods.id, path
FROM pod_tree
JOIN pods ON pods.id=pod_tree.id
JOIN pod_pods ON pod_pods.parent_id = pods.id
WHERE NOT pods.id = ANY(path)
)
SELECT * FROM pod_tree
ORDER BY path;
SQL
sql.chomp
Pod.find_by_sql(sql)
end
我的 SQL 不是特别好,我不知道如何向上和向下导航树结构,以便能够将我上面提到的函数重写为递归 SQL。对于这方面的一些帮助,我将不胜感激。谢谢。
【问题讨论】:
-
您需要添加深度属性吗?这可能会让你穿越。如果你去这里postgresql.org/docs/9.1/queries-with.html 和搜索深度
-
@Lorenz 你能列出模型及其表模式(至少是相关字段)吗?我假设 active 是 AR 范围?
-
@erosenin 我更新了帖子。是的,“活跃”是一个 AR 范围。
标签: sql ruby-on-rails postgresql recursion activerecord