孫要素の条件で子要素の値を返す
はじめに
孫要素をincludes
Prefecture.includes(localities: :sub_locality)
子モデルをキャッシュ&絞込
Prefecture.includes(:localities).references(:localities).where("localities.name = ?", '東京都')
子モデル・孫モデルが存在するレコード抽出
Prefecture.joins(:localities).where("localities.name = ?", '新宿区')
Prefecture.joins(localities: :sub_localities).where("sub_localities.name = ?", '西新宿')
ここまでは、いろいろな記事でもっとわかりやすく書いてるものを参考にしてください。
本題
ここからが本題です!
今回ワタシが苦戦した内容が、「孫要素が必要な条件揃っていたら、子要素の値を返す」というものでした。
上記の例をつくるとすると、
1つの prefecture
の 紐づく locality
に、さらに紐づく sub_locality
が100以上ある場合のみ値を返すコードを作りたい
試行段階
Prefecture.first.localities.joins(:sub_localities).group(:id).having('count_id >= 100').count(:id)
=> {2=>131, 3=>116, 11=>167, 13=>334, 15=>172, 16=>144, 17=>164, 19=>180, 24=>113, 38=>109, 186=>143}
こんな感じの結果が返ってくる。
locality.id
をとれたので、成功!?
しかし、これで locality
を絞るには、
locality_ids = Prefecture.first.localities.joins(:sub_localities).group(:id).having('count_id >= 100').count(:id).keys
のようにして、locality.id
をとってきてから、
Locality.where(id: locality_ids)
と書かないといけない!めんどくさい
結果
一回で絞り込めないかな〜〜と検索してたらドンピシャのサイトがありました。
http://akinov.hatenablog.com/entry/2017/05/13/163911
Prefecture.first.localities.joins(:sub_localities).group(:id).having("count('*') >= ?", 100)
=> #<ActiveRecord::AssociationRelation [#<Locality id: 11, prefecture_id: 1, name: "~~~" ]>
としっかり locality
のデータが返ってきました。
having("count('*') >= ?", 100)
こんな書き方でいけちゃうみたいです!
'*' ここは名前?みたいな感じなのでなんでも良き。(なはず)
Prefecture.first.localities.joins(:sub_localities).group(:id).having("count('*') >= ?", 100).count
=> {2=>131, 3=>116, 11=>167, 13=>334, 15=>172, 16=>144, 17=>164, 19=>180, 24=>113, 38=>109, 186=>143}
ちなみに、count つけるとこんな感じでデータが帰ってきます。
まとめ
- google様での検索ワードってホント大事。
- これが完全正解とは、限らないのでもっといい方法をご存じの方はご教授願います。