I was using active record to get my stories and then generate a CSV, the standard way as done in the rails cast. But I have a lot of rows and it takes minutes. I think if I could get posgresql to do the csv rendering, then I could save some time.
Heres what I have right now:
query = "COPY stories TO STDOUT WITH CSV HEADER;"
results = ActiveRecord::Base.connection.execute(query);
But the results are empty for this query:
=> #<PG::Result:0x00000006ea0488 @connection=#<PG::Connection:0x00000006c62fb8 @socket_io=nil, @notice_receiver=nil, @notice_processor=nil>>
2.0.0-p247 :053 > result.count
=> 0
A better way of knowing:
2.0.0-p247 :059 > result.to_json
=> "[]"
I suspect my controller will look something like this:
format.csv { send_data raw_results }
This works for normal queries, I just can't figure out the SQL syntax to have the CSV results returned to rails.
UPDATE
Got the CSV export from 120000 msec down to 290 msec
My model:
def self.to_csv(story_ids)
csv = []
conn = ActiveRecord::Base.connection.raw_connection
conn.copy_data("COPY (SELECT * FROM stories WHERE stories.id IN (#{story_ids.join(',')})) TO STDOUT WITH (FORMAT CSV, HEADER TRUE, FORCE_QUOTE *, ESCAPE E'\\\\');") do
while row = conn.get_copy_data
csv.push(row)
end
end
csv.join("\r\n")
end
My controller:
send_data Story.to_csv(Story.order(:created_at).pluck(:id))
send_data
straight from DB? I mean, without saving it to thecsv
Array? – Boylstoncsv.join("\r\n")
tocsv.join("\n")
to get it to produce the rows correctly. It was originally adding an extra newline. Not sure if this will affect other non-*nix machines... – Shihself.response_body
as used here. The linked example is incomplete and needslines << "#{row.length.to_s(16)}\r\n"
before yielding a row for a chunked response to work. – Cloth