はじめに
お疲れ様です、りつです。
タイトルの通りなのですが、1対1のリレーションが貼られているテーブルに対して、リレーション先のデータ形式を配列ではなくオブジェクトで取得する方法をまとめました。
文章だとわかりにくいかと思いますので例を示すと、以下のようなイメージです。
- Before
{ "user_id": "ritsu", "profiles": [ // ここが配列形式の中にオブジェクトとして返却されている { "user_name": "りつ", "avatar_url": null } ] }
- After
{ "user_id": "ritsu", "profiles": { // オブジェクト形式で返却されている "user_name": "りつ", "avatar_url": null } }
なお、1対多、多対多のテーブル構造の場合の設定については以下の公式ドキュメントに記載があります。
問題
以下の1対1の関係のテーブルが存在している状況で、ユーザー情報(ユーザーID、ユーザー名、アバターのU)の取得を行いたいと考えていました。
accounts
ユーザーアカウント
No | PK | FK | カラム名 | 型 | NotNull | デフォルト |
---|---|---|---|---|---|---|
1 | 〇 | user_id | varchar | 〇 | ||
2 | password | varchar | 〇 |
profiles
ユーザープロフィール
No | PK | FK | カラム名 | 型 | NotNull | デフォルト |
---|---|---|---|---|---|---|
1 | 〇 | profile_id | uuid | 〇 | ||
2 | 〇 | user_id | varchar | 〇 | ||
3 | user_name | varchar | 〇 | |||
4 | avatar_url | varchar | ||||
5 | introduction | text |
accounts.user_id
とprofiles.user_id
は外部キーでリレーションを設定しているのですが、以下のソースコードを使用してデータ取得を行ったところ、レスポンスのdata
のprofiles
が配列になっていました。
import { User } from '@/domains/user';
import { supabase } from './supabase';
export const fetchUser = async (id: string): Promise<User> => {
const { data, error } = await supabase.from('accounts').select('user_id, profiles(user_name)').eq('user_id', id).single();
if (error) {
throw new Error(error.message);
}
return data;
};
{
"user_id": "ritsu",
"profiles": [
{
"user_name": "りつ",
"avatar_url": null
}
]
}
1対1の関係なので、profiles
の中身は配列ではなく、オブジェクトで取得できればと思い、設定方法を調べました。
解決方法
結論、profiles.user_id
に対して、ユニークキー制約を設定してあげる必要がありました。
Supabaseの管理画面から設定する方法は以下の通りです。
上記設定後、以下のようにデータが返却されるようになりました。
{
"user_id": "ritsu",
"profiles": {
"user_name": "りつ",
"avatar_url": null
}
}
おわりに
まとめ
1対1のリレーションテーブルからデータ取得を行う際は、リレーション先テーブルの外部キーにユニークキー制約の設定が行うと、レスポンスデータがシンプルになる
今回のケースの場合、必要な情報(user_id
、user_name
、avatar_url
)は全てprofiles
テーブルから取得可能なため、リレーションで取得する必要性は低いかもしれません。
ただ、今後両テーブルそれぞれからデータの取得が必要になったパターンを見越して1対1のリレーション取得方法を調べてみました。
どなたかのご参考になれば幸いです。
参考