ruby-on-rails - rails import bulk
Ruby on Rails-Importar datos de un archivo CSV (11)
Me gustaría importar datos desde un archivo CSV a una tabla de base de datos existente. No quiero guardar el archivo CSV, solo tomar los datos de él y ponerlo en la tabla existente. Estoy usando Ruby 1.9.2 y Rails 3.
Esta es mi mesa:
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
¿Me puede dar algún código para mostrarme la mejor manera de hacerlo, gracias?
Es mejor ajustar el proceso relacionado con la base de datos dentro de un bloque de transaction
. El fragmento de código soplo es un proceso completo de sembrar un conjunto de idiomas para el modelo de idioma,
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
El fragmento a continuación es un archivo parcial de languages.csv
,
aa,Afar
ab,Abkhazian
af,Afrikaans
ak,Akan
am,Amharic
ar,Arabic
as,Assamese
ay,Aymara
az,Azerbaijani
ba,Bashkir
...
Es mejor usar CSV :: Table y usar String.encode(universal_newline: true)
. Convierte CRLF y CR a LF
Esto puede ayudar. También tiene ejemplos de código:
http://csv-mapper.rubyforge.org/
O para una tarea de rake por hacer lo mismo:
La gema smarter_csv
se creó específicamente para este caso de uso: para leer datos del archivo CSV y crear rápidamente entradas de la base de datos.
require ''smarter_csv''
options = {}
SmarterCSV.process(''input_file.csv'', options) do |chunk|
chunk.each do |data_hash|
Moulding.create!( data_hash )
end
end
Puede usar la opción chunk_size
para leer N csv-rows a la vez, y luego usar Resque en el bucle interno para generar trabajos que crearán los nuevos registros, en lugar de crearlos de inmediato, de esta forma puede distribuir la carga de generación entradas a múltiples trabajadores.
Ver también: https://github.com/tilo/smarter_csv
La mejor manera es incluirlo en una tarea de rake. Cree el archivo import.rake dentro de / lib / tasks / y coloque este código en ese archivo.
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
Después de eso, ejecute este comando en su rake csv_model_import[file.csv,Name_of_the_Model]
terminal rake csv_model_import[file.csv,Name_of_the_Model]
Puede probar 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
Si esto es lo que desea, también puede considerar deshacerse de la clave primaria de incremento automático de la tabla y configurar la clave principal para el name
. Alternativamente, si hay alguna combinación de atributos que forman una clave principal, utilícela como selector. No es necesario ningún índice, solo lo hará más rápido.
Sé que es una pregunta antigua, pero sigue en los primeros 10 enlaces en google.
No es muy eficiente guardar filas una por una porque causa una llamada a la base de datos en el ciclo y será mejor que lo evite, especialmente cuando necesite insertar grandes porciones de datos.
Es mejor (y significativamente más rápido) usar la inserción por lotes.
INSERT INTO `mouldings` (suppliers_code, name, cost)
VALUES
(''s1'', ''supplier1'', 1.111),
(''s2'', ''supplier2'', ''2.222'')
Puede crear una consulta de este tipo de forma manual y hacer Model.connection.execute(RAW SQL STRING)
(no recomendado) o usar gem activerecord-import
(se lanzó por primera vez el 11 de agosto de 2010) en este caso simplemente coloque datos en rows
matriz y llame a Model.import rows
Si quieres usar SmartCSV
all_data = SmarterCSV.process(
params[:file].tempfile,
{
:col_sep => "/t",
:row_sep => "/n"
}
)
Esto representa datos delimitados por tabulaciones en cada fila "/t"
con filas separadas por nuevas líneas "/n"
Una versión más simple de la respuesta de yfeldblum, que es más simple y funciona bien también con archivos grandes:
require ''csv''
CSV.foreach(filename, :headers => true) do |row|
Moulding.create!(row.to_hash)
end
No es necesario usar with_indifferent_access o symbolize_keys, y no es necesario leer primero el archivo en una cadena.
No mantiene todo el archivo en la memoria a la vez, pero lee en línea por línea y crea un Molding por línea.
Utilice esta joya: https://rubygems.org/gems/active_record_importer
class Moulding < ActiveRecord::Base
acts_as_importable
end
Entonces ahora puedes usar:
Moulding.import!(file: File.open(PATH_TO_FILE))
Solo asegúrate de que tus encabezados coincidan con los nombres de columna de tu tabla
require ''csv''
csv_text = File.read(''...'')
csv = CSV.parse(csv_text, :headers => true)
csv.each do |row|
Moulding.create!(row.to_hash)
end