12/08/2018, 16:11

Bulk inserting data with Gem activerecord-import

1. Bài toán: Khi bạn muốn insert một số lượng lớn (ví dụ 1000 bản ghi) vào cơ sở dữ liệu. Nếu ta thực hiện tuần tự việc insert bản ghi vào database thì muốn insert 1000 bản ghi thì tương đương với việc ta phải thực hiện 1000 câu lệnh sql để insert dữ liệu vào database. Điều này sẽ làm mất thời ...

1. Bài toán:

Khi bạn muốn insert một số lượng lớn (ví dụ 1000 bản ghi) vào cơ sở dữ liệu. Nếu ta thực hiện tuần tự việc insert bản ghi vào database thì muốn insert 1000 bản ghi thì tương đương với việc ta phải thực hiện 1000 câu lệnh sql để insert dữ liệu vào database. Điều này sẽ làm mất thời gian và giảm đi hiệu suất của ứng dụng của bạn.

    1000.times do |i|
  User.create! name: "User  #{i}"
end

Việc insert 1000 bản ghi một cách tuần tự giống như việc bạn sử dụng 1000 chiếc xe để vận chuyển 1000 gói hàng vậy. Vậy tại sao chúng ta ko chúng ta ko sử dụng 1 xe tải cỡ lớn để vận chuyển một lần 10 gói, 100 gói hay thậm chí là 1000 gói hoặc nhiều hơn cùng một lúc? Và Rails hổ chợ chúng ta một chiếc xe tải cỡ lớn để chúng ta có thể sử dụng để vận chuyển số lượng lớn các bản ghi khi chúng ta cần. Và chiếc xe ấy chính là gem Activerecord-import

2. Cài đặt:

Thêm gem "activerecord-import" vào Gemfile và thực hiện bundle install Chú ý: Đối với rails 5.0 cần sử dụng version >= 0.11.0 Đối với rails 4.0cần sử dụng version >= 0.4.0 Đối vớirails 3.2.x trở lên, cần sử dụng version >= 0.3.0

3. Cách sử dụng:

Về cơ bản, muốn thực hiện import số lượng lớn vào database, bạn cần đưa các record vào một mảng sau đó mình dùng mảng đó để import vào database bằng cấu lệnh <Tên Model>.import <Arrays>

4. Import với đầu vào là mảng một Column name và một mảng Values / hoặc dùng Hashes

Ở đây ta sử dụng một mảng columns để lưu tên cột bạn muốn insert, và một mảng values để lưu giá trịtương ứng của từng bản ghi đối với mỗi cột trong mảng columns

columns = [ :name,  :gender ]
values = [["User 1", "Male"], ["User 2", "Female"]]

User.import columns, values

Để tối ưuta có thể thay thế bằng cách dùng Hashes

values = [
  {name: "User 1", gender: "Male"}, 
  {name: "User 2", gender: "Female"}
]

User.import values

5. Import với đầu vào là một mảng các đối tượng

Ta có thể sử dụng một mảng các đối tượng để import cùng một lúc

users = [ 
  Users.new(name: "User 1", gender: "Male"),
  Users.new(name: "User 2", gender: "Female")
]

User.import users

6. Với đầu vào là một mảng các hashes hoặc các objects:

Với trường hợp này ta có thể chỉ rỏ column mà mình muốn insert thay vì insert giá trị của tất cả các trường trong hashes/objects

users = [ 
  Users.new(name: "User 1", gender: "Male"),
  Users.new(name: "User 2", gender: "Female")
]
columns = [:name]

User.import columns, users

# Kết quả trong model User sau khi insert sẽ là
# name    | gender
#---------|--------
# User 1 | NULL   
# User 2 | NULL

7. Options:

  • validate - (true | false) Xác định xem khi import có validate hay không. Mặc định là có validate.
  • ignore - (true | false) một bí danh cho on_duplicate_key_ignore.
  • on_duplicate_key_ignore - (true | false) khi immport sẽ loại bỏ các bản ghi có chứa các phím trùng lặp. Đối với Postgres 9.5+ cho biết thêm ON CONFLICT DO NOTHING, đối với MySQL sử dụng INSERT IGNORE, và đối với SQLite sử dụng INSERT OR IGNORE. Không thể bật trên một import đệ quy.
  • on_duplicate_key_update - (Array hoặc Hash) cho phép import để sử dụng MySQL ON UPDATE KEY UPDATE hoặc Postgres 9.5+ ON CONFLICT DO UPDATE. Xem Thông tin cập nhật khóa trùng lặp bên dưới.
  • synchronize - (một Array các trường hợp ActiveRecord (object) của model mà bạn đang nhập dữ liệu vào). Điều này đồng bộ hoá các trường hợp model hiện có trong bộ nhớ với các cập nhật từ việc import.
  • timestamps - (true | false) import sẽ không thêm timestamps (nếu false) ngay cả khi timestamps được vô hiệu hóa trong ActiveRecord :: Base
  • recursive - (true | false) đối với PostgreSQL khi import sẽ nhập tất cả association has_many / has_one nếu adapter hỗ trợ thiết lập các khóa chính của các đối tượng mới được nhập.
  • batch_size - (một integer) để chỉ định số lượng tối đa của các bản ghi để bao gồm cho mỗi import. Mặc định là tổng số report khi nhập.

8. Kết luận:

Hi vọng bài viết trên có thể giúp ích cho các bạn! Các bạn có thể tìm hiểu thêm ở nguồn: https://github.com/zdennis/activerecord-import

0