【问题标题】:Model database csv bulk insertion from zip file从 zip 文件中的模型数据库 csv 批量插入
【发布时间】:2018-12-21 10:07:41
【问题描述】:

需要使用 activerecord-import 和 ruby​​zip 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 没有隐式转换为字符串

根据本教程:https://mattboldt.com/importing-massive-data-into-rails/

使用此 csv 刷新我的产品模型数据的最佳方法是什么?我必须将文件读入内存(entry.get_input_stream.read)还是保存文件然后导入?

感谢您的帮助

【问题讨论】:

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


    【解决方案1】:

    引发异常 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
    

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

    【讨论】:

      【解决方案2】:

      最后,这是我下载 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 字段中有新日期的情况下更新产品数据库?刷新大型数据库的最佳方法是什么? 谢谢

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2011-07-11
        • 1970-01-01
        • 2019-03-15
        • 1970-01-01
        相关资源
        最近更新 更多