Рубина 2.3.0, Rails 4.2.4, а на самом деле с помощью PostGreSQL вместо SQLiteОбеспечение Rails базы данных запись уникальности при обновлении без прерывания процесса обновления
Обновлены для ясности
У меня есть большой файл CSV файл (обновляемый извне & загружен ежедневно) и написал метод обновления таблицы базы данных Rails. Я не хочу, чтобы метод добавлял все строки в базу данных без проверки уникальности, поэтому я использую это замечательное решение (How do I make a column unique and index it in a Ruby on Rails migration?) с add_index
.
Я использую файл рейка для хранения исполняемого кода обновления, и я ввожу $ rake update_task
в свой терминал (который работает, если таблица не имеет дубликатов с импортированными строками csv). Проблема заключается в том, что база данных ABORTS (rake aborted!
) рейка, когда она встречает первую двойную запись (ERROR: duplicate key value violates unique constraint
).
Что я могу сделать, чтобы удалить/не сохранить дубликаты, избегая прерывания/сбоя? Я не могу просто отбросить таблицу базы данных и перезагрузить ее каждый день. Вот схема:
ActiveRecord::Schema.define(version: 20160117172450) do
# These are extensions that must be enabled in order to support this database
enable_extension "plpgsql"
create_table "tablename", force: :cascade do |t|
t.string "attr1"
t.string "attr2"
t.string "attr3"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
end
add_index "tablename", ["attr1", "attr2", "attr3"], name: "index_tablename_on_attr1_and_attr2_and_attr3", unique: true, using: :btree
end
и моя задача рек в Lib/задачах/содержании file_name.rake:
desc "Download data and update database table"
task :update_task => :environment do
u = CorrectClassName.new
u.perform_this
end
и CorrectClassName
находится в .rb файл в приложении/каталоге directory1:
class CorrectClassName
def perform_this
something = ClassWithUpdateCode.new
something.update_database
end
end
и ClassWithUpdateCode
находится в .rb файл в приложение/каталог directory2:
require 'csv'
class ClassWithUpdateCode
def update_database
csv_update = File.read(Rails.root.join('lib', 'assets', "file_name.csv"))
options = {:headers => true}
csv = CSV.parse(csv_update, options)
csv.each do |row|
tm = TableModel.new
tm.attr1 = row[0]
tm.attr2 = row[1]
tm.attr3 = row[2]
tm.save # maybe I can use a different method or if statement here?
end
end
end
Update: @ решение Kristan работает ниже, но вот где поставить обработку начать/спасения/окончания:
В .rb файл в приложение/каталог directory2:
require 'csv'
class ClassWithUpdateCode
def update_database
csv_update = File.read(Rails.root.join('lib', 'assets', "file_name.csv"))
options = {:headers => true}
csv = CSV.parse(csv_update, options)
csv.each do |row|
tm = TableModel.new
begin
tm.attr1 = row[0]
tm.attr2 = row[1]
tm.attr3 = row[2]
tm.save
rescue ActiveRecord::RecordNotUnique
end
end
end
end
Какую версию PostgreSQL вы используете? 9.5 добавляет поддержку. 'INSERT ... ON CONFLICT DO NOTHING' –
Это может очень хорошо работать (я использую 9.5), Том ... Я просто не пробовал сырой SQL раньше! В какой-то момент в будущем мне нужно будет ускориться, не используя синтаксический анализ csv и, возможно, иметь/копировать и, возможно, ваше предложение SQL здесь. – JHFirestarter