Ruby on Rails - Import Data from a CSV file
我想将CSV文件中的数据导入现有数据库表。 我不想保存CSV文件,只需从中获取数据并将其放入现有表中。 我正在使用Ruby 1.9.2和Rails 3。
这是我的表:
1 2 3 4 5 6 7 8 9 10 11 | 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 |
你能给我一些代码来告诉我最好的方法吗,谢谢。
1 2 3 4 5 6 7 | require 'csv' csv_text = File.read('...') csv = CSV.parse(csv_text, :headers => true) csv.each do |row| Moulding.create!(row.to_hash) end |
更简单的yfeldblum的答案,更简单,也适用于大文件:
1 2 3 4 5 | require 'csv' CSV.foreach(filename, :headers => true) do |row| Moulding.create!(row.to_hash) end |
不需要with_indifferent_access或symbolize_keys,也不需要先将文件读入字符串。
它不会立即将整个文件保存在内存中,而是逐行读取并在每行创建一个Molding。
1 2 3 4 5 6 7 | require 'smarter_csv' options = {} SmarterCSV.process('input_file.csv', options) do |chunk| chunk.each do |data_hash| Moulding.create!( data_hash ) end end |
您可以使用选项
也可以看看:
https://github.com/tilo/smarter_csv
您可以尝试
1 2 3 4 5 6 7 8 9 | 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 |
如果这是你想要的,你也可以考虑从表中删除自动增量主键并将主键设置为
这可以帮助。它也有代码示例:
http://csv-mapper.rubyforge.org/
或者执行相同的rake任务:
http://erikonrails.snowedin.net/?p=212
最好将数据库相关进程包装在
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 | require 'csv' namespace :lan do desc 'Seed initial languages data with language & code' task init_data: :environment do puts '>>> Initializing Languages Data Table' ActiveRecord::Base.transaction do csv_path = File.expand_path('languages.csv', File.dirname(__FILE__)) csv_str = File.read(csv_path) csv = CSV.new(csv_str).to_a csv.each do |lan_set| lan_code = lan_set[0] lan_str = lan_set[1] Language.create!(language: lan_str, code: lan_code) print '.' end end puts '' puts '>>> Languages Database Table Initialization Completed' end end |
下面的代码段是
1 2 3 4 5 6 7 8 9 10 11 | aa,Afar ab,Abkhazian af,Afrikaans ak,Akan am,Amharic ar,Arabic as,Assamese ay,Aymara az,Azerbaijani ba,Bashkir ... |
我知道这是一个古老的问题,但它仍然在谷歌的前10个链接。
逐行保存行并不是非常有效,因为它会导致循环中的数据库调用,您最好避免这种情况,特别是当您需要插入大量数据时。
使用批量插入更好(并且速度更快)。
1 2 3 4 | INSERT INTO `mouldings` (suppliers_code, name, cost) VALUES ('s1', 'supplier1', 1.111), ('s2', 'supplier2', '2.222') |
您可以手动构建此类查询,而不是
或使用gem
有关详细信息,请参阅gem文档
更好的方法是将其包含在rake任务中。在/ lib / tasks /中创建import.rake文件,并将此代码放到该文件中。
1 2 3 4 5 6 7 8 9 10 11 | desc"Imports a CSV file into an ActiveRecord table" task :csv_model_import, [:filename, :model] => [:environment] do |task,args| lines = File.new(args[:filename],"r:ISO-8859-1").readlines header = lines.shift.strip keys = header.split(',') lines.each do |line| values = line.strip.split(',') attributes = Hash[keys.zip values] Module.const_get(args[:model]).create(attributes) end end |
之后在终端
使用这个宝石:
https://rubygems.org/gems/active_record_importer
1 2 3 | class Moulding < ActiveRecord::Base acts_as_importable end |
然后你现在可以使用:
1 | Moulding.import!(file: File.open(PATH_TO_FILE)) |
请确保您的标题与表格的列名相匹配
最好使用CSV :: Table并使用
如果要使用SmartCSV
1 2 3 4 5 6 7 8 | all_data = SmarterCSV.process( params[:file].tempfile, { :col_sep =>"\t", :row_sep =>" " } ) |
这表示每行
"