1

Business:belongs_toというモデルがありますCategory

カテゴリのサンプル階層:

    • レストラン
      • 寿司
      • ピザ
      • 中国語
      • フランス語
      • イタリア語

階層に使用acts_as_treeしています。Category

Businessesレストランカテゴリですべてを見つけるにはどうすればよいですか?

4

3 に答える 3

2

ツリーのような階層内のノードのすべての子孫を取得する場合は、次の2つのオプションがあります。

  1. クラシックを使用しacts_as_tree、選択したカテゴリをプリロードし、クエリのカスケードを開始して、葉(それ以上の子のないノード)のみを取得するまで、すべての子、孫などを取得します。このアプローチは、思ったほど良いものです。

  2. 入れ子集合やクロージャーツリーなど、より高度なツリー表現を使用します。これらの表現では、1つのクエリで特定のノードのすべての子孫を取得できます。

次に、収集したカテゴリを取得し、ビジネスでクエリを実行します。

Business.where(:category => categories)

(技術的な説明:ネストされたセット)

ネストされたセット表現の下で、各ノードには2つのインデックスがあり、次のように割り当てられます。各ノードが東と西の2つの窓のある家であり、木が多かれ少なかれすべての子供が親の北。それで、あなたはルートハウスの東から始めて、あなたが出会う窓に連番を置きます。道路を横断することは決してありません。北にそれ以上道路がない家を一周することだけが許可されています。最後に、ルートハウスに戻り、西の窓に番号を付けます。

割り当てられた番号には、次のプロパティがあります。

  • すべての東のウィンドウには偶数があり、すべての西のウィンドウには奇数があります(0から始めた場合)
  • 各家のデルタ(西と東の数の差)は常に1+子孫の家の数です
  • 家Hのすべての子孫の家は、東と西の番号がH自身の番号の間に厳密に含まれます。
  • 逆もまた真であり、番号がHの番号の間に厳密に含まれているすべての家は、実際にはHの子孫です。
  • 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
于 2012-10-30T15:03:51.320 に答える
0
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))
于 2012-10-30T12:48:57.623 に答える
0

あなたはただ次のようなことをすることはできません:

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

それはあなたにビジネスのリストを返すはずです。あまり良くないようですが、もっと最適な方法があるはずだと思います。

うまくいけば、とにかくそれはあなたに思考のためのいくつかの食べ物を与えるはずです。

于 2012-10-30T12:50:26.690 に答える