2010-07-27 14 views
9

Obiettivo: Utilizzando un compito cron (o altro evento programmato) per aggiornare il database con l'esportazione notturno di dati da un sistema esistente.Come scrivere un'attività Rake per importare i dati nell'app Rails?

si crea Tutti i dati/aggiornati/cancellati in un sistema esistente. Il sito Web non si integra direttamente con questo sistema, quindi l'app per i binari deve semplicemente riflettere gli aggiornamenti che appaiono nell'esportazione dei dati.

Ho un file .txt di ~ 5.000 prodotti che assomiglia a questo:

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

Tutti i valori sono stringhe racchiuse tra virgolette (") che sono separati da due punti (:)

campi sono :

  • id: ID univoco; alfanumerico
  • name: nome del prodotto; qualsiasi carattere
  • colonne di attributi: stringhe; qualsiasi carattere (ad es. dimensioni, peso, colore, dimensione)
  • vendor_name: stringa; qualsiasi carattere
  • vendor_id: unico ID fornitore; numerico

Le informazioni del fornitore non sono normalizzate nel sistema corrente.

Quali sono le migliori pratiche qui? Va bene cancellare le tabelle dei prodotti e dei fornitori e riscrivere con i nuovi dati ad ogni ciclo? O è meglio aggiungere solo nuove righe e aggiornare quelle esistenti?

Note:

  1. Questi dati saranno utilizzati per generare Orders che persisterà attraverso le importazioni di database notturne. OrderItems dovrà essere collegato agli ID prodotto specificati nel file di dati, quindi non possiamo fare affidamento su una chiave primaria ad auto-incremento per essere uguale per ogni importazione; l'ID alfanumerico univoco dovrà essere utilizzato per unire products a order_items.
  2. Idealmente, vorrei l'importatore per normalizzare i dati fornitore
  3. non riesco a utilizzare le istruzioni SQL di vaniglia, quindi immagino che avrò bisogno di scrivere un compito rake al fine di utilizzare Product.create(...) e Vendor.create(...) sintassi stile.
  4. Questo sarà attuato su EngineYard

risposta

14

non vorrei cancellare i prodotti e fornitori tabelle su ogni ciclo. Questa è un'app per rails? Se è così, ci sono alcuni simpatici aiutanti ActiveRecord che ti torneranno utili.

Se si dispone di un modello prodotto record attivo, si può fare:

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! 

Il find_or_initialize si ricerca il prodotto nel database per l'id specificato, e se non lo trova, lo farà creane uno nuovo.La cosa veramente a portata di mano di fare in questo modo, è che ActiveRecord salverà solo il database se uno dei dati è cambiato, e si aggiorna automaticamente i campi timestamp che avete in tabella (updated_at) di conseguenza. Un'altra cosa, dato che dovresti cercare i record per mezzo dell'identificatore (id dal file), mi assicurerei di aggiungere un indice su quel campo nel database.

Per eseguire un'operazione di rake, aggiungerei un file rake alla directory lib/tasks dell'app rails. Lo chiameremo data.rake.

All'interno data.rake, sarebbe simile a questa:

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 

che chiamare il compito rastrello, usare "i dati rake: import" dalla riga di comando.

+0

ho provato questo, ma sto ottenendo l'errore non definito variabile locale o un metodo 'dati' 'per il main: Object'. Qualche idea sul perché questo potrebbe accadere? – Nick

+0

Il problema era che 'do' dati namespace doveva essere cambiato in' namespace: do' dati. – Nick

0

Poiché i prodotti non cambiano davvero così spesso, il modo migliore che vorrei vedere è quello di aggiornare solo i record che cambiano.

  1. Prendi tutti i delta
  2. aggiornamento di massa utilizzando una singola istruzione SQL

Se si hanno il codice di normalizzazione nei modelli, è possibile utilizzare Product.create e Vendor.create altrimenti sarebbe solo un eccesso. Inoltre, cerca di inserire più record in una singola transazione SQL, è molto più veloce.

+0

come indicato nella mia domanda, I __cannot__ usa un'istruzione SQL vaniglia. –

0
  • Creare un'attività di importatore rake che è cronned
  • analizzare il file riga per riga usando CSV Più veloce o tramite vaniglia rubino come:

file.each fare | line | products_array = line.split (":") fine

  • Spalato ogni riga sulla ":" e spingere in in un hash
  • Utilizzare un find_or_initialize per popolare il db come ad esempio:

    Product.find_or_initialize_by_name_and_vendor_id ("foo", 111)

+0

Perché stai usando 'find_or_initialize_by_name_and_vendor_id'? Questo suggerisce il prodotto 'accept_nested_attributes_for: vendor'? –

Problemi correlati