从zip文件模型数据库csv批量插入

时间:2018-12-21 10:07:42

标签: ruby-on-rails zip activerecord-import

需要使用activerecord-import和rubyzip gem将zip文件中的csv数据导入到我的产品模型中。

此代码有效(下载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 :(得分:0)

由于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

您可以在这些文档中阅读更多内容:

答案 1 :(得分:0)

最后,这是我的代码,用于下载一个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字段中有新日期时,才如何更新产品数据库?刷新大数据库的最佳方法是什么? 谢谢