[Rails] 批次建立資料

陳漢庭
Oct 31, 2020

--

upsert_all

第一次看到這篇的時候就躍躍欲試,很想要使用upsert_all去批次建資料。終於在接到任務的時候有機會用到了。在使用的時候…,咦?rails logger跳出created_at 是必填欄位請務必填寫。那時候心裡想著:「不會吧,該不會真的有雷吧」。帶著各種問號的我,找到原來upsert_all 沒有透過ActiveRecord的callback跟驗證。

原本預計是這樣用:

Category.upsert_all(sheet_data)# sheet_data 裡面為要創建的資料
# 下方為sheet_data內每一個元素的長相
{
parent_id: parent.id,
description: name,
path: path,
created_at: Time.current,
updated_at: Time.current,
}
# sheet_data 的長相
# sheet_data = [{第一筆}, {第二筆}, {第三筆}, ...]

由於upsert_all為直接對資料庫層做操作,如果覺得創建的資料不用經過任何的驗證跟回呼的話,upsert_all是最好的方法,也可以省很多效能。類似的用法還有upsert, insert, insert_all,在這篇可以看到更多用法。

create

create就是耳熟能詳的創建資料的方法,但create可以批次建立檔案這件事情大家知道嗎?這是我最近才知道的。

Category.create([{first-item}, {second-item}, {third-item}, ..., {last-item}])

如果不需要查找資料是否存在的話,批次建立create是一個最好的選擇。不過在我目前所遇到的情境,也就是匯資料的時候可能因為某種原因斷線而資料匯入到一半的情況,就不適用了。

find_or_create_by

近期在搜尋如何批次使用find_or_create_by的方式,沒有找到什麼結果。看起來就只能用以下用法一筆一筆迭代跟使用find_or_create_by 了。

sheet_data.each {|data| Category.find_or_create_by(data)}

匯資料 Services

以下為匯資料流程。通常從別的部門收到的excel檔案裡面都會有數張工作表,資料表在程式碼的代號為sheet或者style_sheets。我們匯對sheets做迭代去做資料處理,像以下就是使用sheets.each do {}分別對每一個資料表做操作。

我的做法是把每一個工作表的資料全部整理成一個陣列之後再建立,是比較functional programming的寫法。這邊使用compact (濾掉空值)、flatten(平坦陣列)、uniq(去除陣列中重複的元素)來對陣列做後處理才做刪除的動作。

之所以沒有把全部的資料塞成一坨是因為實際上匯的資料太多筆,陣列的記憶體空間不夠,這會造成一起創建的時候會漏建很多筆資料。

--

--

陳漢庭
陳漢庭

Written by 陳漢庭

由於零散的紀錄過了一段時間之後就看不懂了,於是為了強迫自己用故事的方式記錄學到的東西,就開啟我的發文之路。

No responses yet