- ベストアンサー
Railsで1対多の関連で指定した子を持たない親の検索方法
- Rails4で1対多関連のモデルに対して指定した子を持たない親の検索方法について教えてください。
- 現在は除外する値を指定して親を検索するという方法で実装していますが、もっとスマートな方法があれば教えてください。
- 子の条件を複数指定できるようにしたいです。
- みんなの回答 (3)
- 専門家の回答
質問者が選んだベストアンサー
SQLで書くのなら、NOT EXISTSを使えば1つにできそうなのですが、 RailsのActiveRecordでは無理なようです。 Arelで可能なようですが、かなり分かりにくいコードになってしまうようです。 分かりやすさと速さから見て、No.2のコードが良さそうです。(ちゃんと動きますよね) 興味がありましたら、上のキーワードで検索してみてください。 ActiveRecordは検索結果をRuby変数に変換する時にでデータ量が多いと遅くなります。 今回の場合はデータ量が少ないと思いますので、速度にはあまり影響しないと思います。
その他の回答 (2)
- ki073
- ベストアンサー率77% (491/634)
ちょっと勘違いでした。一つのSQL発行で済ませたかったのですが、ActiveRecordですぐに思いついたのは excludes = [ '除外1', '除外2',... ] exclude_ids=Parent.joins(:children).where(children: {value: excludes}).uniq.pluck(:id) Parent.where.not(id: exclude_ids) excludes配列の要素数よりexclude_idsが同じか少なくなるので そんなに遅くはないとは思いますが もう少し考えてみますが
お礼
ありがとうございます すごくスマートなコードになりました SQL発行回数も大幅に減ったので処理が軽くなりました 「特定の子をもたない親」の検索を直接的に行うのはやはり難しいのでしょうか 全体から「特定の子をもつ親を除外」というのが、なんだかちょっと気持ち悪い感じがします # SQLでもどうかけばいいかよくわからない
- ki073
- ベストアンサー率77% (491/634)
以下でいけると思います excludes = [ '除外1', '除外2',... ] Parent.joins(:children).where.not(children: {value: excludes})
お礼
返答ありがとうございます 試してみたところ 親A:子[1,2,3] 親B:子[4,5,6] に対し、1を持たない、という条件で教えていただいた式を実行すると [A,A,B,B,B]が返ってきてしまいます もしかするとモデルの設計自体が悪いのでしょうか……
お礼
NOT EXISTS、実際に使ったことが無いので存在をすっかり忘れていました…… Arelはor検索の際に少し検索したことがありますが 今回はそこまで速さの追及はしていないのでわかりやすさを重視してみます 補足説明までありがとうございました