[英]Adjacency data structure to nested hash
I have the following model in rails: 我在rails中有以下模型:
class Model < ActiveRecord::Base
# id — integer
# name — string
# model_id — integer
belongs_to :parent, class_name: 'Model', foreign_key: 'model_id'
has_many :children, class_name: 'Model', foreign_key: 'model_id'
end
I am using adjacency structure, which can have infinite depth. 我正在使用邻接结构,它可以具有无限深度。 I am on a Postgres database using recursive selects. 我使用递归选择在Postgres数据库上。
What will be the most sane way to get a nested hash of objects? 获得嵌套的对象哈希的最理智的方法是什么? I tried to select instances of Model
and sort them, yet could not bring this to any usable result. 我试图选择Model
实例并对它们进行排序,但却无法将其带入任何可用的结果。
Lets say I have four Model
instances saved in my database: Model_1
, Model_2
, Model_3
and Model_4
. 比方说,我有四个Model
保存在我的数据库实例: Model_1
, Model_2
, Model_3
和Model_4
。 Model_3
is a child of Model_2
and Model_4
is a child of Model_3
. Model_3
是Model_3
的子Model_2
, Model_4
是Model_4
的子Model_3
。
Here is an output I am trying to achieve (a nested hash of Model
instances): 这是我想要实现的输出( Model
实例的嵌套哈希):
{
#<Model_1...> => {},
#<Model_2...> => {
#<Model_3...> => {
#<Model_4...> => {}
}
}
}
Any ideas? 有任何想法吗?
Update: Tree is already recovered — either as a CollectionProxy, Relation or any other array-ish data structure. 更新:树已经恢复 - 作为CollectionProxy,Relation或任何其他array-ish数据结构。 I wan't to sort that tree into the hash of nested hashes. 我不想将那棵树排成嵌套哈希的哈希值。
I would name it parent_id
field. 我将它命名为parent_id
字段。
belongs_to :parent, class_name: "Model"
has_many :children, class_name: "Model", foreign_key: "parent_id"
When you have the hash, you would use sort
or sort_by
: 当你有哈希时,你会使用sort
或sort_by
:
http://www.ruby-doc.org/core-2.1.0/Enumerable.html#method-i-sort_by http://www.ruby-doc.org/core-2.1.0/Enumerable.html#method-i-sort_by
def sort(hash)
hash.sort { |m1, m2| m1.id <=> m2.id }
sort(hash.children)
end
First, define the ff method inside your Model class: 首先,在Model类中定义ff方法:
def to_hash
if children.empty?
{self => {}}
else
{self => children.inject({}) {|hash, model| hash.merge(model.to_hash) } }
end
end
Then do the ff to get the output you want: 然后执行ff以获得所需的输出:
top_level_models = #code that queries top-level models while eager-loading all nested children
hash_of_nested_models = top_level_models.inject({}) {|hash, ancestor| hash.merge(ancestor.to_hash) }
The hash argument that you pass to includes should cover the depth of your nesting. 传递给包含的哈希参数应该覆盖嵌套的深度。 The argument passed to includes
above will be the nesting for children with a depth of 3 descendants. 传递给上面includes
的参数将是具有3个后代深度的子项的嵌套。 For as long as you includes all the nested children in your where
query, generating the hash will not do any more db queries. 只要您在where
查询中包含所有嵌套子项,生成哈希将不再执行任何数据库查询。
Hope that helps! 希望有所帮助!
Getting AR to do this without N+1 queries would be difficult. 在没有N + 1个查询的情况下让AR执行此操作将非常困难。 Will have to write something that works with the data in memory. 将不得不写一些与内存中的数据一起使用的东西。
You would have to write a custom function which looks something like: 您必须编写一个类似于以下内容的自定义函数:
def to_hash
root_hash = {}
# Load all the model into memory and into a hash to allow faster access when we have the id
models = Hash[Model.all.collect {|m| [m.id, m]}]
# The resultant hash for each child
models_with_hash = Hash[map.values.collect {|m| [m.id, {}]} ]
# Stitch them together
models.each do |id, m|
if m.model_id.nil?
root_hash.merge! m => models_with_hash[m.id]
else
# should name model_id to parent_id
models_with_hash[m.model_id].merge! m => models_with_hash[m.id]
end
end
root_hash
end
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.