2016-05-03 7 views
1

モデル 'battle'とモデル 'category'の関係は、has_and_belongs_to_manyです。私は特定のカテゴリに関係しないすべての戦いを見つけようとしています。 は、私がこれまでに実行しようとしましたがある:has_and_belongs_to_many関係の最初の行を取得する方法postgres sql

Battle.all.includes(:categories).where("(categories[0].name NOT IN ('Other', 'Fashion'))") 

、このエラーが発生しました:ActiveRecord::StatementInvalid: PG::DatatypeMismatch: ERROR: cannot subscript type categories because it is not an array

おかげで、 ロテム

+0

あなたがする必要があります。 "(categories.name NOT IN( 'Other'、 'Fashion'))") –

答えて

2

categories[0].nameの使用は、カテゴリのname列に有効なSQLリファレンスではありません。インスタンス化Battleレコードの:categories関係にと熱心に負荷適切なCategoryのActive Recordオブジェクト - Battle用とCategoryのための1 - このコードは2つのクエリを実行することを

Battle.includes(:categories).reject do |battle| 
    ['Other', 'Fashion'].include? battle.categories.map(&:name) 
end 

注:

はこれを試してみてください。これは、ガイドのin detailsに記載されているN + 1個のクエリを防ぐのに役立ちます。

上記のコードは、望ましくないカテゴリを持つレコードを削除する前に、メモリALL Battleのレコードに最初にロードすることにも注意してください。あなたのデータによっては、これは禁止されることがあります。

battle_ids_sql = Battle.select(:id).joins(:categories).where(categories: {name: ['Other' ,'Fashion']}).to_sql 
Battle.where("id NOT IN (#{battle_ids_sql})") 

battle_ids_sqlがあなたの望ましくないの1を持って戦いIDを返すSQL文です:あなたが唯一の関連ActiveRecordのオブジェクトがインスタンス化されますように、SQLクエリを制限したい場合は、以下のようなもので逃げることができカテゴリ。実際に実行されるSQLは、その内部SQLにないすべてのBattleレコードをフェッチします。これは効果的ですが、控えめに使用してください。このようなクエリは、すばやく維持するのが難しくなる傾向があります。

あなたはおよそjoinsincludesと他の二つの関連した方法(eager_loadpreloadhereを学ぶことができます。

+0

これは望ましい結果セットを与えません - それはカテゴリにあるすべての戦いを返します「その他」や「ファッション」以外。バトルが「X」カテゴリと「ファッション」カテゴリの場合、それが返されます。バトルがどのカテゴリにもない場合、それは返されません。 –

+0

あなたは非常に正しいです。それをキャッチするためにありがとう。私は答えを修正しました。 – AmitA

+0

優秀 - 最初の方法に固有の制限を記述するのに良い仕事(「拒否」を使用して)興味深い問題 - 問題の記述は単純ですが、解決策はありません! –

関連する問題