我在Rails應用程序中有幾個模型。假設它是產品和銷售。獲取帶有統計信息的導軌模型
產品有很多銷售,並且銷售屬於產品。
我所希望做的是讓所有產品(可能條件下),每個產品旁邊的列表提供銷售,類似於數的計數:
- 產品1(10)
- 產品2(22)
雖然輸出是相當簡單的,我想不出一個很好的方式來收集數據,而無需使用SQL。
我還應該補充一點,我可能也想對銷售應用一個條件。
我在Rails應用程序中有幾個模型。假設它是產品和銷售。獲取帶有統計信息的導軌模型
產品有很多銷售,並且銷售屬於產品。
我所希望做的是讓所有產品(可能條件下),每個產品旁邊的列表提供銷售,類似於數的計數:
雖然輸出是相當簡單的,我想不出一個很好的方式來收集數據,而無需使用SQL。
我還應該補充一點,我可能也想對銷售應用一個條件。
如果你正確地宣佈associations,這是因爲以下簡單:
Product.find(:all, :include => :sales).each do |product|
puts product.name + " (#{product.sales.size})"
end
編輯:
關聯是可以搜索的,如果您需要申請條件豐富的館藏:
@products = Product.find(:all, :include => :sales)
@products.each do |product|
# Find product sales only from yesterday
yesterdays_sales = product.sales.find(:all, :conditions => { :created_at => Date.yesterday }
end
如果你不介意把從數據庫相關的銷售對象到應用程序,然後東西like this笑uld做這份工作:
但請留意它。
# Preload all the Sales for our Products, sow we won't end up with `N+1` issue.
selected_products = Product.all :joins => :sales, :conditions => {'orders.successful' => true}
# Then use it like a normal association:
selected_products.each { |p| puts p.sales.size }
問候,
德米特里。
您的解決方案有N + 1個問題。 'Product.all'調用使用'WHERE'條件中的'join'表。在隨後對p.sales的調用中,將向數據庫提交新查詢以獲取與該產品關聯的銷售。我在這裏給出了詳細的答覆:(http://stackoverflow.com/questions/2338605/getting-a-rails-model-with-statistics/2339708#2339708)。 – 2010-02-26 05:44:11
@KandadaBoggu,非常感謝。我相信'sales.size'不會執行查詢,因爲它應該用':join'加載。 需要去看看。 – 2010-02-26 05:52:35
不用擔心。因爲你,我能夠證實我一直對'連接'有懷疑。 – 2010-02-26 07:41:46
如果您主要對計算每件產品的銷售量感興趣,則應該使用counter_cache
功能。這將確保您始終從products
表中獲取計數,而不是計算JIT計數。
# products table should have a column called sales_count
class Product < ActiveRecord:Base
has_many :sales
end
class Sales < ActiveRecord:Base
belongs_to :product, :counter_cache => true
end
軌道將遞增/遞減在創建/刪除銷售sales_count
列的照顧。 現在你可以通過執行獲得銷售數量如下:
Product.first.sales_count
有條件地計算一個product
對象的sales
請執行以下操作:
Product.first.sales.count(:conditions => ["amount > ? ", 200])
有條件地計算了一批product
就做如下:
#returns a ordered hash
product_sales_count = Product.count(:joins => [:sales], :conditions =>
["amount > ? ", 200], :group =>"products.id").each do |product_id, sales_count|
p "Product #{product_id} = #{sales_count}"
end
# If you need the product objects get all of them in one call and match the count
products = Product.find(:all, :joins => [:sales], :conditions =>
["amount > ? ", 200], :group =>"products.id").each do |product|
p "Product #{product.name} = #{product_sales_count[product.id]}"
end
這種方法將節省大量的旅行到數據庫。
'Product.first.sales.count(:conditions => [「amount>?」,200])'將執行每個產品的查詢。那麼,如果需要有條件的計數,有什麼意義呢:counter_cache? – 2010-02-26 01:12:44
它以'N + 1'結尾。 – 2010-02-26 01:13:40
正如我在我的回答中所提到的,如果他主要是在沒有條件的情況下計算銷售額,他應該選擇counter_cache。我已經修改了我的答案,以解決條件情形下的N + 1問題。這又取決於他的用例。 – 2010-02-26 01:27:50
這不是一個答案,而是三個答案比較這個問題。我已經給出了我的答案。在的:joins
和:include
的工作中存在混淆。所以我花了一些時間分析三個解決方案的SQL日誌。
方法1:獲取使用count
#To return the sales count for each product
ps_count_hash = Product.count(:joins => [:sales], :group => "products.id") # sql 1.1
# To print the product id and sales count
ps_count_hash.each do | product_id, sales_count|
p "Product#{product_id} - (#{sales_count})"
end
# To print the product details and sales count
# get all the products associated
Product.find_all_by_id(ps_count_hash.keys).each |product| #sql 1.2
p "Product[id = #{product.id}, name = #{product.name}] - (#{ps_count_hash[product.id]})"
end
方法2的銷售數:通過join
Product.find(:all, :joins=>[:sales]).each do |product| #sql 2.1
p "Product[id = #{product.id}, name = #{product.name}] - (#{product.sales.size})" # sql 2.2 - 2.(2+N)
end
方法3獲得的產品:通過include
獲取產品
Product.find(:all, :include=>[:sales]).each do |product| #sql 3.1 and 3.2
p "Product[id = #{product.id}, name = #{product.name}] - (#{product.sales.size})"
end
現在讓我們來看看這三個方法生成的SQL語句
SQL語句的方法1 - 2 SQL
SELECT count(*) AS count_all, products.id AS products_id FROM `products` INNER JOIN `sales` ON sales.product_id = products.id GROUP BY products.id
SELECT `products`.* FROM `products` WHERE (`products`.`id` IN (1,2))
SQL語句的方法2 - 2 SQL
SELECT * FROM `products`
SELECT `sales`.* FROM `sales` WHERE (`sales`.product_id IN (1,2))
方法3的SQL語句 - N + 1 SQL
SELECT `products`.* FROM `products` INNER JOIN `sales` ON sales.product_id = products.id
SELECT * FROM `sales` WHERE (`sales`.product_id = 1)
SELECT * FROM `sales` WHERE (`sales`.product_id = 2)
最佳由銷售計數產物(與出銷售信息)的方法:方法1
最佳由銷售計數產物(與銷售信息)的方法:方法2
方法3具有N + 1問題。所以這是沒有爭議的。
在這裏你有'N + 1'的問題。 – 2010-02-26 00:37:08
沒有理由過早優化。協會是The Rails Way,任何看着他的代碼的Rails開發者都會很熟悉。如果這成爲瓶頸,他總是可以優化。 – 2010-02-26 00:42:28
這不是一個過早的優化。只需使用':include'或':join'即可。你不會爲此花費任何時間。 爲什麼我們應該提前編寫錯誤的代碼,因爲現在我們可以用完全相同的工作編寫更好的代碼,因爲知道它是不好的。 – 2010-02-26 00:47:17