2017-08-11 9 views
0

私はモデルを持っており、この例ではProductモデルと呼ぶことができます。私はこのデータベースに約200kレコードあり、半分はactiveactive: true)で、半分はそうではありません。ユーザーが商品の検索を行っているときには、アクティブな商品のみを表示する必要があります。私のコードは次のようなものになります。そうRails:検索結果をメモリにロードせずにフィルタリングする方法

def self.search 
    products = Products.where(active: true).order("`foo` = 'BAR'") 
    products = products.where(other_filters) 
    products = products.where(more_filters) 
    .. 
end 

がメモリに最初の100kのアクティブなものをロードする(最初where戻っ100000puts products.sizeをやって)、これらは、その後の連鎖where句で約20回以上ダウン濾過し、最後にページが表示されるので、25個しか表示されません。これらの結果をより効率的にフィルタリングする方法はありますか?

+0

あなたはActiveRecordのようないくつかのORMを使用していますか? .whereを連鎖するだけで、データベースがすべてのフィルタに一致するものを返すようにすることができます。 –

+0

ActiveRecordチェーンでは、 '.where'は1つのクエリを作成します。また、['.merge'](http://api.rubyonrails.org/classes/ActiveRecord/SpawnMethods.html#method--merge)を使ってスコープをマージすることもできます。あなたは本当にそれを解決するためのよりclunkyな方法を探していますか? – max

答えて

3

whereデータベースクエリを実行せず、代わりにActiveRecord::Relationのインスタンスを返します。実際、あなたの例ではデータベースクエリはまったく実行されません。それは関係にますます多くの条件を繋ぐだけです。

結果を返すために実際にレコードが必要なときに、データベースへの実際のクエリが実行されます。データベースからのロードをトリガーするメソッドの例をいくつか示します。countfirsteachmaploadまたはinspectです。

中間結果(例:puts)を出力しない限り、あなたは安全であり、必要なクエリは実行しないと言います。ちょうどすべての条件をまとめてください。

ところであなたはproducts変数を削除することによって、あなたのコードを簡素化することができます:

def self.search 
    Products 
    .where(active: true) 
    .order("`foo` = 'BAR'") 
    .where(other_filters) 
    .where(more_filters) 
    # ... 
end 
+0

ちょっとしたメモとして、 'to_s'はクエリを実行しませんが、' inspect'はクエリを実行します。 'puts'は配列のように(私が仮定すると)同じように、各要素が新しい行に出力されます(' each'または同等のものを実行します) –

関連する問題