Ruby on Rails - 从CSV文件导入数据

fre*_*est 195 csv import ruby-on-rails

我想将CSV文件中的数据导入现有的数据库表.我不想保存CSV文件,只需从中获取数据并将其放入现有表中.我正在使用Ruby 1.9.2和Rails 3.

这是我的表:

create_table "mouldings", :force => true do |t|
  t.string   "suppliers_code"
  t.datetime "created_at"
  t.datetime "updated_at"
  t.string   "name"
  t.integer  "supplier_id"
  t.decimal  "length",         :precision => 3, :scale => 2
  t.decimal  "cost",           :precision => 4, :scale => 2
  t.integer  "width"
  t.integer  "depth"
end
Run Code Online (Sandbox Code Playgroud)

你能给我一些代码来告诉我最好的方法吗,谢谢.

yfe*_*lum 364

require 'csv'    

csv_text = File.read('...')
csv = CSV.parse(csv_text, :headers => true)
csv.each do |row|
  Moulding.create!(row.to_hash)
end
Run Code Online (Sandbox Code Playgroud)

  • 你能告诉我把这段代码放在哪里吗? (3认同)
  • 这种方法效率低下!在巨大的CSV文件上,ram使用量猛增.下面的那个更好. (3认同)
  • 您可以将其放入Rake任务,控制器操作或任何您喜欢的位置。 (2认同)
  • @daveatflow:是的,请参阅下面的答案,该答案一次读取一行文件. (2认同)

Tom*_*Leu 196

更简单的yfeldblum的答案,更简单,也适用于大文件:

require 'csv'    

CSV.foreach(filename, :headers => true) do |row|
  Moulding.create!(row.to_hash)
end
Run Code Online (Sandbox Code Playgroud)

不需要with_indifferent_access或symbolize_keys,也不需要先将文件读入字符串.

它不会立即将整个文件保存在内存中,而是逐行读取并在每行创建一个Molding.


Til*_*ilo 11

smarter_csv宝石是专为这个用例发布:读取从CSV文件中的数据,并快速创建数据库条目.

  require 'smarter_csv'
  options = {}
  SmarterCSV.process('input_file.csv', options) do |chunk|
    chunk.each do |data_hash|
      Moulding.create!( data_hash )
    end
  end
Run Code Online (Sandbox Code Playgroud)

您可以使用该选项一次chunk_size读取N csv-rows,然后在内部循环中使用Resque生成将创建新记录的作业,而不是立即创建它们 - 这样您就可以分散生成条目的负载多个工人.

另见:https: //github.com/tilo/smarter_csv

  • 由于包含了CSV类,我觉得最好使用它而不是添加或安装额外的gem.当然,您没有建议在应用程序中添加新的gem.添加一系列单独的宝石是非常容易的,每个宝石都用于特定目的,在您知道之前您的应用程序具有过多的依赖性.(我发现自己有意识地避免添加任何宝石.在我的商店,我们需要证明我们的队友能够加入.) (3认同)
  • @Tass 对 CSV 处理进行分块、提高速度并节省内存可能是添加新 gem 的一个很好的理由;) (3认同)
  • @Tass,添加一系列单独的方法也很容易,每个方法都有一个特定的目的,在您知道之前,您的应用程序有过多的逻辑需要维护。如果一个 gem 工作正常,维护良好,并且使用很少的资源,或者可以隔离到相关环境(即生产任务的暂存),那么在我看来*总是*使用该 gem 的更好选择。Ruby 和 Rails 都是为了编写更少的代码。 (2认同)

Sea*_*ere 5

你可以试试Upsert

require 'upsert' # add this to your Gemfile
require 'csv'    

u = Upsert.new Moulding.connection, Moulding.table_name
CSV.foreach(file, headers: true) do |row|
  selector = { name: row['name'] } # this treats "name" as the primary key and prevents the creation of duplicates by name
  setter = row.to_hash
  u.row selector, setter
end
Run Code Online (Sandbox Code Playgroud)

如果这是您想要的,您还可以考虑从表中删除自动增量主键并将主键设置为name. 或者,如果存在形成主键的某些属性组合,请将其用作选择器。不需要索引,它只会让它更快。