3

介紹的Ruby-on-Rails的3.2:導出CSV與大型數據集(100,000條記錄)

我有了多個表,部分和一些沒有關聯的工具軟件。

一些表格將被要求保存約100,000條目。

該應用程序在Ruby 1.9上使用Rails 3.2並託管在Heroku上。如果需要,我可以訪問工作人員。

問題的要求

的應用一個重要要求是,讓用戶在數據導出爲CSV - 這一個要求是,讓用戶過濾他們想輸出什麼樣的數據,但我目前並不擔心這一點,正如你將從下面的數據中看到的那樣,我已經硬編碼了要導出哪些數據,但是這確實排除了創建一個rake任務來導出整個表。

此外,實現的方法必須考慮到允許多個表使用,以避免unnessacrobat代碼重複。

目前的解決方案

我實現我的應用程序的delayed_job和執行CSV產生的工作。在做這件事時,我正在按照'abdullah'在http://www.ayokasystems.com/blog/delegating-long-running-jobs-in-rails/找到的解決方案。

想法是以CSV格式生成數據並將其保存在UserJobs表中的LONGTEXT字段中,以允許用戶在下次完成後下載。

的問題

,直到我同時運行的10萬條記錄工作從上面的教程中使用的方法適用於我的應用程序的罰款。爲了克服這個問題我曾試圖清涼find_each功能添加到執行方法,但延遲在職職工報告回它會嘗試處理這一個錯誤每次:

[Worker(host:*** pid:18637)] ReportJob failed with NoMethodError: undefined method `each' for #<Title:0x007ff20c1ec1b0> - 0 failed attempts 
[Worker(host:*** pid:18637)] ReportJob failed with NoMethodError: undefined method `each' for #<Title:0x007ff20ec47f18> - 1 failed attempts 
[Worker(host:*** pid:18637)] 2 jobs processed at 10.5219 j/s, 2 failed ... 

我對執行方法的代碼是:

def perform 
    Title.find_each do |titles| 
    csv_data = CSV.generate do |csv| 
     titles.each do |t| 
     csv << t.to_csv 
     end 
    end 
    user_job = UserJob.find(user_job_id) 
    user_job.update_attribute :data, csv_data 
    end 
end 

任何人都可以看到問題可能是什麼,我想我剛剛做了一個愚蠢的錯誤,我如何循環的事情。

對於如何完成相關要求的任何其他建議,我非常歡迎,但請記住我與Heroku的限制。

+0

已經編輯了我的代碼,因爲我剛剛看到我忘了將CSV.generate分配給csv_data以用於更新記錄。 – Billy 2012-04-20 12:28:35

回答

3

您正試圖每個但在這種情況下,標題是標題(不陣列)的情況下,進行迭代。

csv_vals = [] 
columns = [:name, :release_date, :studio] 

Title.find_each(:select => columns) do |title| 
    columns.each {|value| csv_vals << "#{title[value]}"} 
end 

# comma separated string 
csv_string = csv_vals.join(',') 

有更優雅的方式來制定CSV字符串,但我懶得試驗。

什麼是重要的是,你只在你需要的列做SELECT。對於100 000條增加了大量帶寬較少的DB通信的記錄。只需find_each您可以獲得每一行的所有列,而且您不需要它們。

+0

感謝您的回答,但是另一個要求是,此方法將在未來接受來自其他表的數據,因此我不想實現選擇。 我知道在問題中我列出了會導致你做出的假設的具體領域,但這僅僅是爲了參考,我已經修改了問題來解決這個問題。 但很好的答案,並會記住這個技術的未來。 – Billy 2012-04-20 12:18:47

+0

您可以將列參數作爲方法參數,代碼將與不同的列一起工作。在任何情況下記住,如果你要find_each和那裏有很多記錄,請使用select :) – 2012-04-20 12:24:12

+0

很酷,會採用這種方法!謝謝海豚! – Billy 2012-04-20 12:30:23

1

find_each產生單個記錄到塊,而不是集合,因此您的錯誤在單個記錄上調用each。看看find_in_batches,或修復您的代碼使用單獨的記錄:

Title.find_each do |title| 
    CSV.generate do |csv| 
    csv << title.to_csv 
    end 
    user_job = UserJob.find(user_job_id) 
    user_job.update_attribute :data, csv_data 
end 
+0

順便說一句,這只是爲了解決您的特定錯誤 - 我沒有提供關於代碼效率的意見。 – Thilo 2012-04-20 11:55:51

+0

感謝您選擇並參考api! – Billy 2012-04-20 12:25:27