2010-07-27 8 views
9

Objetivo: Usar una tarea CRON (u otro evento programado) para actualizar la base de datos con la exportación nocturna de datos desde un sistema existente.¿Cómo escribir una tarea de Rake para importar datos a la aplicación Rails?

Todos los datos se crean/actualizan/eliminan en un sistema existente. El sitio web no se integra directamente con este sistema, por lo que la aplicación Rails simplemente debe reflejar las actualizaciones que aparecen en la exportación de datos.

Tengo un archivo de ~ 5.000 productos .txt que tiene este aspecto:

"1234":"product name":"attr 1":"attr 2":"ABC Manufacturing":"2222" 
"A134":"another product":"attr 1":"attr 2":"Foobar World":"2447" 
... 

Todos los valores son cadenas entre comillas dobles (") que están separados por dos puntos (:)

campos son :

  • id: id único; alfanumérico
  • name: nombre del producto; cualquier carácter
  • columnas de atributo: cadenas; cualquier carácter (por ejemplo, tamaño, peso, color, dimensión)
  • vendor_name: cadena; cualquier carácter
  • vendor_id: id único del vendedor; numérico

La información del vendedor no está normalizada en el sistema actual.

¿Cuáles son las mejores prácticas aquí? ¿Está bien eliminar las tablas de productos y proveedores y reescribir con los nuevos datos en cada ciclo? ¿O es mejor solo agregar nuevas filas y actualizar las existentes?

Notas:

  1. Estos datos serán utilizados para generar Orders que persistirá a través de la importación de base de datos todas las noches. OrderItems tendrá que estar conectado a los identificadores de productos que se especifican en el archivo de datos, por lo que no podemos confiar en que una clave principal de incremento automático sea la misma para cada importación; la identificación alfanumérica única tendrá que ser utilizada para unir products a order_items.
  2. Idealmente, me gustaría que el importador para normalizar los datos de los proveedores
  3. que no puedo utilizar declaraciones de vainilla SQL, así que me imagino que voy a necesitar para escribir una tarea rake con el fin de utilizar la sintaxis de estilo y Product.create(...)Vendor.create(...).
  4. Esto se implementará en EngineYard

Respuesta

14

Yo no eliminar los productos y los vendedores de mesas en cada ciclo. ¿Es esta una aplicación de rieles? De ser así, hay algunos ayudantes ActiveRecord realmente útiles que te resultarán útiles.

Si usted tiene un modelo de producto registro activo, que puede hacer:

p = Product.find_or_initialize_by_identifier(<id you get from file>) 
p.name = <name from file> 
p.size = <size from file> 
etc... 
p.save! 

El find_or_initialize será buscar el producto en la base de datos del identificador se especifica, y si no lo encuentra, se crea uno nuevoLo realmente útil para hacerlo de esta manera es que ActiveRecord solo guardará en la base de datos si alguno de los datos ha cambiado, y automáticamente actualizará los campos de marca de tiempo que tenga en la tabla (updated_at) en consecuencia. Una cosa más, ya que estaría buscando registros por el identificador (id del archivo), me aseguraría de agregar un índice en ese campo en la base de datos.

Para hacer una tarea de rake para lograr esto, agregaría un archivo rake al directorio lib/tasks de la aplicación Rails. Lo llamaremos data.rake.

Dentro data.rake, se vería algo como esto:

namespace :data do 
    desc "import data from files to database" 
    task :import => :environment do 
    file = File.open(<file to import>) 
    file.each do |line| 
     attrs = line.split(":") 
     p = Product.find_or_initialize_by_identifier(attrs[0]) 
     p.name = attrs[1] 
     etc... 
     p.save! 
    end 
    end 
end 

que llamar la tarea rastrillo, utilizar "datos de rastrillo: importación" de la línea de comandos.

+0

he intentado esto, pero estoy consiguiendo el error 'variable local o método no definido 'datos' para las principales: Object'. ¿Alguna idea de por qué esto podría estar pasando? – Nick

+0

El problema era que '' namespace data do' tenía que cambiarse a 'namespace: data do'. – Nick

0

Dado que los productos en realidad no cambian tan a menudo, lo mejor que vería es actualizar solo los registros que cambian.

  1. Obtener todos los deltas
  2. actualización masiva utilizando una sola sentencia SQL

Si tiene el código de normalización de los modelos, se puede usar Product.create y Vendor.create o de lo contrario sería solo una exageración. Además, mire en la inserción de múltiples registros en una sola transacción SQL, es mucho más rápido.

+0

como se indicó en mi pregunta, no puedo usar una declaración de SQL vainilla. –

0
  • Crear una tarea importador de rastrillo que se cronned
  • analizar el archivo línea por línea usando CSV más rápido a través de vainilla o de rubí como:

file.each hacer | línea | products_array = linea.split (":") final

  • Dividir cada línea de la ":" y empuje en un hash
  • Use un find_or_initialize para poblar su base de datos, tales como:

    Product.find_or_initialize_by_name_and_vendor_id ("foo", 111)

+0

¿Por qué está utilizando 'find_or_initialize_by_name_and_vendor_id'? ¿Sugiere esto un producto 'accepts_nested_attributes_for: vendor'? –

Cuestiones relacionadas