9 Stimmen

Wie Rake Aufgabe zu schreiben, um Daten zu Rails app importieren?

Das Ziel: Verwendung einer CRON-Aufgabe (oder eines anderen geplanten Ereignisses) zur Aktualisierung der Datenbank durch nächtlichen Export von Daten aus einem bestehenden System.

Alle Daten werden in einem bestehenden System erstellt/aktualisiert/gelöscht. Die Website ist nicht direkt mit diesem System verbunden, so dass die Rails-App lediglich die Aktualisierungen widerspiegeln muss, die im Datenexport erscheinen.

Ich habe eine .txt Datei mit ~5.000 Produkten, die wie folgt aussieht:

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

Alle Werte sind Zeichenketten, die in doppelte Anführungszeichen ( " ), die durch Doppelpunkte getrennt sind ( : )

Felder sind:

  • id : eindeutige Kennung; alphanumerisch
  • name : Produktname; beliebiges Zeichen
  • Attributspalten: Strings; beliebige Zeichen (z. B. Größe, Gewicht, Farbe, Dimension)
  • vendor_name : Zeichenkette; beliebiges Zeichen
  • vendor_id : eindeutige Verkäufer-ID; numerisch

Die Lieferanteninformationen sind im derzeitigen System nicht normalisiert.

Was sind hier die besten Praktiken? Ist es in Ordnung, die Tabellen "Produkte" und "Lieferanten" zu löschen und bei jedem Zyklus mit den neuen Daten neu zu schreiben? Oder ist es besser, nur neue Zeilen hinzuzufügen und bestehende zu aktualisieren?

Anmerkungen:

  1. Diese Daten werden verwendet, um Orders die durch nächtliche Datenbankimporte erhalten bleiben. OrderItems muss mit den in der Datendatei angegebenen Produkt-IDs verknüpft werden, so dass wir uns nicht darauf verlassen können, dass ein automatisch inkrementierender Primärschlüssel bei jedem Import derselbe ist; die eindeutige alphanumerische ID muss verwendet werden, um die products a order_items .
  2. Im Idealfall möchte ich, dass der Importeur die Verkäuferdaten normalisiert
  3. Ich kann keine einfachen SQL-Anweisungen verwenden, also muss ich wohl eine rake Aufgabe, um die Product.create(...) y Vendor.create(...) Stil-Syntax.
  4. Dies wird auf EngineYard umgesetzt werden

14voto

smnirven Punkte 1488

Ich würde die Tabellen "Produkte" und "Lieferanten" nicht bei jedem Zyklus löschen. Ist dies eine Rails-App? Wenn ja, gibt es einige wirklich nette ActiveRecord Helfer, die für Sie nützlich sein würde.

Wenn Sie ein aktives Produktdatensatzmodell haben, können Sie das tun:

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!

Die Funktion find_or_initialize sucht in der Datenbank nach dem Produkt mit der von Ihnen angegebenen ID, und wenn es nicht gefunden wird, wird ein neues Produkt erstellt. Das wirklich Praktische an dieser Vorgehensweise ist, dass ActiveRecord nur dann in der Datenbank speichert, wenn sich die Daten geändert haben, und alle Zeitstempelfelder, die Sie in der Tabelle haben (updated_at), automatisch entsprechend aktualisiert. Und noch etwas: Da Sie die Datensätze anhand des Bezeichners (id aus der Datei) suchen, würde ich sicherstellen, dass Sie einen Index für dieses Feld in der Datenbank hinzufügen.

Um eine Rake-Aufgabe zu erstellen, um dies zu erreichen, würde ich eine Rake-Datei in das Verzeichnis lib/tasks Ihrer Rails-App hinzufügen. Wir nennen sie data.rake.

In data.rake würde es etwa so aussehen:

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

Um die Rake-Aufgabe aufzurufen, verwenden Sie "rake data:import" in der Befehlszeile.

0voto

Greg Punkte 4341

Da sich die Produkte nicht so oft ändern, ist es am besten, nur die geänderten Datensätze zu aktualisieren.

  1. Alle Deltas erhalten
  2. Massenaktualisierung mit einer einzigen SQL-Anweisung

Wenn Sie Ihren Normalisierungscode in den Modellen haben, könnten Sie Product.create und Vendor.create verwenden, andernfalls wäre es nur ein Overkill. Prüfen Sie auch, ob Sie mehrere Datensätze in einer einzigen SQL-Transaktion einfügen können, das geht viel schneller.

0voto

nicholasklick Punkte 1212
  • Erstellen einer Rake-Aufgabe für den Importer, die nach dem Croning-Prinzip abläuft
  • Parsen Sie die Datei Zeile für Zeile mit Faster CSV oder mit Vanilla Ruby:

file.each do |line| products_array = line.split(":") end

  • Jede Zeile am ":" teilen und in eine Raute einfügen
  • Verwenden Sie eine find_or_initialize, um Ihre db wie zu bevölkern:

    Product.find_or_initialize_by_name_and_vendor_id("foo", 111)

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X