2011-04-26 2 views
1

저는 항상 모델에 맞지 않는 결과를 쿼리하고 얻는 방법을 궁금해했습니다. LINQ를 사용하여 익명 개체로 투영하는 방법과 비슷합니다.Rails 3 Query : 가장 많이 본 제품/기사/기타를 얻는 방법?

# Product.rb 
class Product < ActiveRecord::Base 
    has_many :product_views 

    # attributes: id, name, description, created_at, updated_at 
end 

# ProductView.rb 
class ProductView < ActiveRecord::Base 
    belongs_to :product 

    # attributes: id, product_id, request_ip, created_at, updated_at 
end 

는 기본적으로 나는 그것이 있었다 뷰의 수와 함께 제품의 목록 (바람직하게는 단지 아이디와 이름)을 얻을 필요가 :

그래서 여기에 간단한 스키마입니다. 분명히 뷰 수 desc로 정렬됩니다.

내가 얻을하고자하는 SQL입니다 :
select 
    p.id, 
    p.name,  
    count(pv.product_id) as views 
from 
    product_views pv 
inner join 
    products p on pv.product_id = p.id 
group by 
    pv.product_id 
order by 
    count(product_id) desc 

나는 다음과 유사하지만 내가 갖는 ProductView의 객체를 시도, 난 그냥 배열 또는 무엇이든을 좀하고 싶습니다.
ProductView.includes(:product) 
      .group('product_id') 
      .select("products.id, products.name, count(product_id)") 

이런 종류의

일반 SQL 또는 LINQ를 사용하여 사소한,하지만 난 레일에서 쿼리 이런 종류의 자신에 stucked 찾을 수 있습니다. 어쩌면 나는 유명한 레일 방식을 생각하고 있지 않을 것입니다. 아마도 뭔가 명백한 것을 놓치고있을 것입니다.

그러면 레일즈 3에서 이러한 종류의 쿼리를 어떻게 수행 할 것인가? 이 일을 개선하기위한 제안은 언제나 환영합니다.

이 모델을 사용하여 할 수있는 방법이 있는지 당신이

답변

2

:

Product.includes(:product_views).all.map { |p| [p.id, p.name, p.product_views.size] } 

이 그 다음으로 정렬 그러나 당신이 원하는.

+0

굉장한 솔루션. 배열 배열 대신 해시 배열을 얻으려고 조금 변경했습니다. 감사! – emzero

+0

기꺼이 도와 드리겠습니다!내가 사용하는 코드는 해시를 반환하지만 간결하게하려고했습니다. :-) – MarkD

+0

내가 싫어할 수있는 유일한 이유는 내부 조인 대신 IN 절을 사용하고 있다는 것입니다. – emzero

0

모르겠어요 감사드립니다. 나는 아마도 리조트에 갈 것이다 :

Product.connection.select_rows(sql) 

당신에게 배열의 배열을 줄 것이다. 차라리 배열이 해시 인 경우 select_all을 사용할 수 있습니다.

+0

모델을 수정할 수는 있지만 일반적인 '추적'테이블 인 것 같습니다. 제품 테이블과 product_views (또는 hits) 테이블. 또한, 이런 종류의 쿼리 (가장 많이 본 제품/기사/무엇이든을 얻으려면)는 매우 인기가 있으며 나는 그것을 할 수있는 쉬운 방법이 없다는 것을 이상하게 여깁니다. – emzero

-1

이 시도 :

@product = Product.find(#product_id) 
@product_views = @product.product_views.count 

(출처 - http://ar.rubyonrails.org/classes/ActiveRecord/Calculations/ClassMethods.html#M000292)이 도움이

희망!

+0

특정 제품에 대해 계산할 필요가 없습니다. 뷰순으로 정렬 된 제품 목록이 필요합니다. 모든 제품을 반복하고 계산을하지 않는 한 도움이되지 않습니다. 물론 실용적인 솔루션은 아닙니다. – emzero

3

당신은 당신이 찾고있는 무엇을 할 Arel을 사용할 수 있습니다

products = Product.arel_table 
product_views = ProductView.arel_table 

# expanded for readability: 
sql = products.join(product_views) 
       .on(product_views[:product_id].eq(product[:id])) 
       .group(product_views[:product_id]) 
       .order('views DESC') 
       .project(products[:id], 
         products[:name], 
         product_views[:id].count.as('views')) 

products_with_views = Product.connection.select_all(sql.to_sql) # or select_rows to just get the values 

예, 그것은 긴하지만, Arel는 관계없이 재사용 할 수있는 복잡한 쿼리를 작성하는 처리 할 수있는 매우 현명한 방법이다 데이터베이스 유형. 제품 클래스의 클래스 메소드 내에서

+0

내가 찾고있는 것 같습니다. 나중에 당신의 코드를 시험해 보겠습니다. 감사합니다 – emzero

관련 문제