こんにちは。
この記事では、Rails + PostgreSQL で Array型のカラムを使用する方法を紹介します。
「Array型を使わずにテーブル分けろ」ってツッコミはしないでください。
array型ってどういうの?
端的にいうと、
1つのカラムに複数の値を格納できるデータ型
です。
例えば、librariesテーブルにbooksカラムというArray型のカラムを作成した場合、
「こころ」、「源氏物語」という複数の値を1つのカラムに保存することができます。
実際にデータを作ると以下のようになります。
postgres=# INSERT INTO libraries VALUES('books', ARRAY['こころ', '源氏物語']);
INSERT 0 1
postgres=# SELECT * FROM libraries ;
name | books
----------+---------
東京図書館 | {こころ,源氏物語}
Railsで使う方法
1. migration
array型にするカラムに array: true
オプションを付与します。
class CreateLibraries < ActiveRecord::Migration[6.0]
def change
create_table :libraries do |t|
t.string :name
t.string :books, array: true, default: []
t.timestamps
end
end
end
2. Create
保存する値を配列で渡します。
Library.create(name: "東京図書館", books: ["こころ", "源氏物語"])
3. Show
カラムを参照すると、配列で値が返ってきます。
library = Library.find_by(name: "東京図書館")
library.books
=> ["こころ", "源氏物語"]
4. Query
調べてみると、Array型の検索が高機能だったので、ユースケースごとに紹介します。
ユースケースとしては以下の4つがあるとします。
- 「こころ」を蔵書した図書館を探したい
- 「こころ」と「源氏物語」の両方を蔵書した図書館を探したい
- 「こころ」と「源氏物語」のどちらかを蔵書した図書館を探したい
- 2冊以上の本を蔵書している図書館を探したい
順番に確認していきます。
「こころ」を蔵書した図書館を探したい
=
を使用します。
Library.where("'こころ' = ANY (books)")
「こころ」と「源氏物語」の両方を蔵書した図書館を探したい
@>
を使用します。
Library.where('books @> ARRAY[?]::varchar[]', ['こころ', '源氏物語'])
「こころ」と「源氏物語」のどちらかを蔵書した図書館を探したい
&&
を使用します。
Library.where('books && ARRAY[?]::varchar[]', ['こころ', '源氏物語'])
2冊以上の本を蔵書している図書館を探したい
array_length
を使用します。
Library.where("array_length(books, 1) >= 2")
まとめ
いかがでしたでしょうか。
Array型を使用すれば、手軽に複数の値を1つのカラムに格納することができ、様々なユースケースに対応した検索をすることができます。
どうしても「1つのテーブルでまとめたい」という時はArray型を是非検討してみてください。