Business
:belongs_toというモデルがありますCategory
カテゴリのサンプル階層:
- 根
- レストラン
- 寿司
- ピザ
- 中国語
- フランス語
- イタリア語
- レストラン
階層に使用acts_as_tree
しています。Category
Businesses
レストランカテゴリですべてを見つけるにはどうすればよいですか?
Business
:belongs_toというモデルがありますCategory
カテゴリのサンプル階層:
階層に使用acts_as_tree
しています。Category
Businesses
レストランカテゴリですべてを見つけるにはどうすればよいですか?
ツリーのような階層内のノードのすべての子孫を取得する場合は、次の2つのオプションがあります。
クラシックを使用しacts_as_tree
、選択したカテゴリをプリロードし、クエリのカスケードを開始して、葉(それ以上の子のないノード)のみを取得するまで、すべての子、孫などを取得します。このアプローチは、思ったほど良いものです。
入れ子集合やクロージャーツリーなど、より高度なツリー表現を使用します。これらの表現では、1つのクエリで特定のノードのすべての子孫を取得できます。
次に、収集したカテゴリを取得し、ビジネスでクエリを実行します。
Business.where(:category => categories)
(技術的な説明:ネストされたセット)
ネストされたセット表現の下で、各ノードには2つのインデックスがあり、次のように割り当てられます。各ノードが東と西の2つの窓のある家であり、木が多かれ少なかれすべての子供が親の北。それで、あなたはルートハウスの東から始めて、あなたが出会う窓に連番を置きます。道路を横断することは決してありません。北にそれ以上道路がない家を一周することだけが許可されています。最後に、ルートハウスに戻り、西の窓に番号を付けます。
割り当てられた番号には、次のプロパティがあります。
したがって、ツリーに新しい要素を挿入するのはコストがかかりますが(多くのインデックスを更新する必要があります)、子孫全体(すべての子、孫など)を取得するのは非常に簡単です。 「西」の数字は、選択したカテゴリの東と西の間にあります。実際には少し上手くいくことができますが、ここでは問題ではありません。
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 = 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))
あなたはただ次のようなことをすることはできません:
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
それはあなたにビジネスのリストを返すはずです。あまり良くないようですが、もっと最適な方法があるはずだと思います。
うまくいけば、とにかくそれはあなたに思考のためのいくつかの食べ物を与えるはずです。