Массовая вставка базы данных модели csv из zip-файла - PullRequest
0 голосов
/ 21 декабря 2018

Требуется импортировать данные CSV из zip-файла в модель моего продукта с использованием activerecord-import и rubyzip gem.

Этот код работает (загрузите zip и отобразите имя csv)

desc "Import products data from web"
task import_product: :environment do
    url = "https://example.com"
    dir = "db/example_zip.zip"

    File.open(dir, "wb") do |f|
        f.write HTTParty.get(url).body
    end

    Zip::File.open(dir) do |zip|
        zip.each do |entry|
            entry.name
        end
    end
end

В "цикле zip.each" я пробовал это:

items = []
CSV.foreach(entry, headers: true) do |row|
  items << Item.new(row.to_h)
end
Item.import(items)

У меня следующая ошибка TypeError: нет неявного преобразования Zip :: Entry в String

Согласно этому руководству:https://mattboldt.com/importing-massive-data-into-rails/

Каков наилучший способ обновить данные модели моего продукта с помощью этого CSV?Нужно ли мне читать файл в память (entry.get_input_stream.read) или сохранять файл и затем импортировать его?

Спасибо за помощь

Ответы [ 2 ]

0 голосов
/ 26 декабря 2018

Наконец, вот мой код для загрузки zip-файла и импорта данных в мою модель продукта

require 'zip'
require 'httparty'
require 'active_record'
require 'activerecord-import'

namespace :affiliate_datafeed do
    desc "Import products data from Awin"
    task import_product_awin: :environment do
        url = "https://productdata.awin.com"
        dir = "db/affiliate_datafeed/awin.zip"

        File.open(dir, "wb") do |f| 
            f.write HTTParty.get(url).body
        end

        zip_file = Zip::File.open(dir)
        entry = zip_file.glob('*.csv').first
        csv_text = entry.get_input_stream.read
        products = []

        CSV.parse(csv_text, :headers=>true).each do |row|
            products << Product.new(row.to_h)
        end
        Product.import(products)
  end
end

Но следующий вопрос: как обновить базу данных продукта, только если продукт не существуетили если в поле last_updated есть новая дата?Каков наилучший способ обновить большую базу данных?Спасибо

0 голосов
/ 21 декабря 2018

Исключение TypeError: no implicit conversion of Zip::Entry into String вызвано тем, что метод CSV.foreach принимает путь к файлу (который является String объектом) в качестве аргумента, но вместо этого вы отправляете ему объект Zip::Entry.

Вы можете просто извлечьzip-файл и загрузите его содержимое непосредственно в память:

Zip::File.open(dir) do |zip|
  zip.each do |entry|
    items = []
    CSV.new(entry.get_input_stream.read, headers: true).each do |row|
      items << Item.new(row.to_h)
    end
    Item.import(items)
  end
end

Или, если CSV-файл слишком большой, вы можете сохранить распакованные файлы, а затем использовать CSV.foreach для загрузки этих файлов:

Zip::File.open(dir) do |zip|
  zip.each do |entry|
    csv_file = File.join(File.dirname(dir), entry.name)
    entry.extract(csv_file)
    items = []
    CSV.foreach(csv_file, headers: true) do |row|
      items << Item.new(row.to_h)
    end
    Item.import(items)
  end
end

Вы можете прочитать больше в этой документации:

...