4

2 つのオブジェクトを比較するクエリを作成しようとしていますが、それらが同じ場合id、レコードはフェッチされません。私が持っているのはこれです:

@channels.each do |channel|
  unless @guide_channels.where(:id => channel.id).exists?
    @dropdown_channels = @dropdown_channels.where(:id => channel.id)
  end
end

これによりクエリが作成されますが、すべての値の間に AND が配置されますが、これは私が考えているものではありません。「または」演算子が必要です。使用できる「orwhere」関数はありますか、それとも比較関数を使用してこれを行うより良い方法はありますか?

4

2 に答える 2

1

重要なのは.where()、オブジェクトのメソッドがAR::Relation一連の条件に条件を追加しAND、クエリの実行時にこれらの条件をまとめることです。

あなたがしなければならないのは、次のようなクエリですNOT IN

# select all the ids for related @guide_channels
# if @channels comes from a query (so it's a ActiveRecord::Relation):
guide_ids = @guide_channels.where(:id => @channels.pluck(:id)).pluck(:id)
#  use .where(:id => @channels.map {|c| c.id}) instead if @channels is just an array

# then use the list to exclude results from the following.
@dropdown_channels = @dropdown_channels.where("id NOT IN (?)", guide_ids.to_a)

最初のクエリは、 にエントリがあるチャネルのすべての ID を蓄積します@guide_channels。2 つ目は最初の結果を使用して、見つかったチャネルをドロップダウンの結果から除外します。

于 2012-10-31T14:49:38.820 に答える
0

この奇妙な振る舞いは、ActiveRecordによるスコープの遅延評価によるものです。何が起こるかというと

@dropdown_channels = @dropdown_channels.where(:id => channel.id)

の値を実際に使用するまでDBにクエリを送信しません。実際に使用する@dropdown_channelsと、すべての条件が1つの大きなクエリに連結されます。これが、条件間にANDを取得する理由です。

ActiveRecordにスコープのロードを強制するために、allスコープまたはスコープのいずれかを使用できますfirst。次に例を示します。

@dropdown_channels = @dropdown_channels.where(:id => channel.id).first

これにより、ActiveRecordはその場でクエリを計算し、結果をすぐに返し、遅延評価のスコープを蓄積しません。

別のアプローチは、それらすべてのchannels_idを累積し、それぞれに対してクエリを作成するのではなく、後で1つのクエリで取得することです。このアプローチは、DBリソースに関してより費用効果があります。これを達成するために:

dropdown_channels_ids = []
@channels.each do |channel|
  unless @guide_channels.where(:id => channel.id).exists?
    dropdown_channels_ids << channel.id
  end
end
@dropdown_channels = @dropdown_channels.where(:id => dropdown_channels_ids)
于 2012-10-31T14:44:03.047 に答える