ОБНОВЛЕНИЕ:
Пожалуйста, обратите внимание на новый Ruby Gem " smarter_csv " на случай, если вы хотите обновить MongoDB из записей CSV-файлов.Он имеет множество полезных функций, в том числе фрагментирование больших файлов, и возвращает результаты в виде фрагментов в виде массивов хэшей.
См. Также:
Обновленный ответ:
require 'smarter_csv'
filename = '/tmp/college_majors.csv'
# The :key_mapping renames one column and ignores the column "Level"
# Each line of the CSV-file is converted into a hash with keys: :major_code, :code
n = SmarterCSV.process(filename, {:chunk_size => 10,
:key_mapping => {:level => nil} }) do |chunk|
# We're passing a block in to process each resulting hash / row (block takes array of hashes).
# If the CSV-file is large, we can process it in parallel in chunks (using Resque Workers).
# For this we would extract the following block into a Resque worker and instead just create
# a new Resque job for each chunk.
chunk.each do |hash|
c = College.find_by_code( hash[:code] )
c.majors ||= []
c.majors << majorcode_to_name( hash[:major_code] )
c.save
end
end
Предыдущий ответ:
Предполагая, что у вас уже есть метод majorcode_to_name ():
require 'csv'
csvAA = CSV.read( csv_filename ) # returns an array of arrays
# => [["Code", "MajorCode", "Level"], ["123456", "98765", "2"], ["123456", "99999", "2"]]
headersA = csvAA.shift # extract the headers into an array
# => ["Code", "MajorCode", "Level"]
# turn the "array of arrays" which contain the CVS data, into an "Array of Hashes":
csvAH = csvAA.map {|row| Hash[*headersA.zip(row).flatten] }
# => [{"Code"=>"123456", "MajorCode"=>"98765", "Level"=>"2"}, {"Code"=>"123456", "MajorCode"=>"99999", "Level"=>"2"}]
csvAH.each do |rowH|
c = College.find_by_code( rowH['Code'] )
c.majors ||= [] # initialize as empty array if it doesn't exist
c.majors << majorcode_to_name( rowH['MajorCode'] )
c.save
end
Если ваш CSV-файл действительно большой, вы можете немного изменить этот код, чтобы вам не приходилось считывать все данные в ОЗУ
require 'csv'
headersA = nil
CSV.foreach do |row|
if headersA.nil?
headersA = row
else
rowH = Hash[*headersA.zip(row).flatten]
c = College.find_by_code( rowH['Code'] )
c.majors ||= [] # initialize as empty array if it doesn't exist
c.majors << majorcode_to_name( rowH['MajorCode'] )
c.save
end
end
РЕДАКТИРОВАТЬЯ должен был упомянуть, почему я преобразовал результат CSV.read в массив хэшей. Основная причина - сделать код независимым от порядка заголовков в файле CSV, что делает код немного более устойчивым.