Rails原始查询csv格式,通过控制器返回

pen*_*ner 14 csv postgresql pg ruby-on-rails-4 rails-activerecord

我正在使用活动记录来获取我的故事,然后生成CSV,这是在rails cast中完成的标准方式.但我有很多行,需要几分钟.我想如果我能让posgresql做csv渲染,那么我可以节省一些时间.

这是我现在所拥有的:

query = "COPY stories TO STDOUT WITH CSV HEADER;"
results = ActiveRecord::Base.connection.execute(query);
Run Code Online (Sandbox Code Playgroud)

但是此查询的结果为空:

 => #<PG::Result:0x00000006ea0488 @connection=#<PG::Connection:0x00000006c62fb8 @socket_io=nil, @notice_receiver=nil, @notice_processor=nil>> 
2.0.0-p247 :053 > result.count
 => 0 
Run Code Online (Sandbox Code Playgroud)

更好的了解方式:

2.0.0-p247 :059 >   result.to_json
 => "[]" 
Run Code Online (Sandbox Code Playgroud)

我怀疑我的控制器看起来像这样:

format.csv { send_data raw_results }
Run Code Online (Sandbox Code Playgroud)

这适用于普通查询,我只是无法弄清楚将CSV结果返回到rails的SQL语法.

UPDATE

CSV输出从120000毫秒下降到290毫秒

我的模特:

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
Run Code Online (Sandbox Code Playgroud)

我的控制器:

send_data Story.to_csv(Story.order(:created_at).pluck(:id))
Run Code Online (Sandbox Code Playgroud)

mu *_*ort 14

AFAIK你需要copy_data在底层的PostgreSQL数据库连接上使用这个方法:

- (对象)copy_data(sql)

呼叫序列:

conn.copy_data( sql ) {|sql_result| ... } -> PG::Result
Run Code Online (Sandbox Code Playgroud)

执行复制过程以将[sic]数据传输到服务器或从服务器传输[sic]数据.

这将COPY通过发出SQL 命令#exec.对此的响应(如果命令中没有错误)是PG::Result传递给块的对象,其状态代码为PGRES_COPY_OUT或PGRES_COPY_IN(取决于指定的复制方向).然后,应用程序应使用#put_copy_data#get_copy_data接收或传输数据行,并在完成时应从块返回.

还有一个例子:

conn.copy_data "COPY my_table TO STDOUT CSV" do
  while row=conn.get_copy_data
    p row
  end
end
Run Code Online (Sandbox Code Playgroud)

ActiveRecord的原始数据库连接的包装器不知道是什么copy_data,但您可以使用raw_connection它来解包它:

conn = ActiveRecord::Base.connection.raw_connection
csv  = [ ]
conn.copy_data('copy stories to stdout with csv header') do
  while row = conn.get_copy_data
    csv.push(row)
  end
end
Run Code Online (Sandbox Code Playgroud)

这将为您留下一系列CSV字符串csv(每个数组条目一个CSV行),您csv.join("\r\n")可以获得最终的CSV数据.