✏️ 이 글은 사이드프로젝트 "스무디"를 개발하며 알게된 점은 정리하여 기록한 글입니다.
이 글은 supabase를 사용하여 관계 테이블을 가져오기까지의 과정을 정리하였습니다.
결론만 궁금하시다면, 글 가장 하단에 있습니다 😊
supabase에서 관계 테이블을 가져오기까지 과정
서버에서 데이터를 가져올 때 관계된 테이블에서 데이터를 함께 가져와야 하는 경우가 몇차례 있었다.
프로필을 예로 들자면, 아래와 같은 항목 중 참여한 프로젝트의 항목은 project 테이블에서 해당 유저의 프로젝트를 가지고 오는 방식으로 하고 싶었다. 관계를 형성해야 하는 것이었다.
projects 테이블과 profiles 테이블 구성은 아래와 같았다.
# projects 테이블
create table
public.projects (
id bigint generated by default as identity,
title text not null,
description text not null,
repo_url text not null,
image_url text null,
profile_id uuid not null,
inside_project boolean not null,
created_at timestamp with time zone not null default now(),
modified_at timestamp with time zone not null default now(),
constraint projects_pkey primary key (id),
constraint public_projects_profile_id_fkey foreign key (profile_id) references profiles (id)
) tablespace pg_default;
# profiles 테이블
create table
public.profiles (
id uuid not null,
email text not null,
user_name text not null,
avatar_url text null,
created_at timestamp with time zone not null default now(),
modified_at timestamp with time zone not null default now(),
cover_letter text null,
tech_tags text[] null,
hard_skills text[] null,
soft_skills text[] null,
position text null,
constraint profiles_pkey primary key (id),
constraint profiles_id_fkey foreign key (id) references auth.users (id) on delete cascade
) tablespace pg_default;
1. 처음에는 해당 유저의 프로필과 프로젝트를 각각 조회하는 방식 사용
profiles 테이블에서 해당 유저를 가져오고, projects 테이블에서 해당 유저의 프로젝트를 가져오는 방식이었다.
const { data, error } = await supabase
.from("profiles") // 프로필 가져오기
.select()
.eq("id", targetId);
const { data, error } = await supabase
.from("projects") // 프로젝트 가져오기
.select()
.eq("id", targetId);
하지만 이는 유저의 프로필 정보를 조회할 때마다 2번의 요청을 보내야했다. 이를 좀 더 효율적으로 가져오는 방법이 있을 것 같아서 다른 방법을 찾아보기 시작했다.
2. 더 효율적인 방법을 위해 공식문서 탐색
테이블간의 관계를 활용해 관계가 있는 테이블을 함께 가져오는 방법이 있을 것 같아서 공식문서를 찾아보다 아래와 같은 부분을 발견했다.
Fetch data의 여러 옵션들 중 내가 원했던 참조 테이블에서 데이터를 가져오는 방법이었다.
🔗 출처 https://supabase.com/docs/reference/javascript/select
const { data, error } = await supabase
.from('cities')
.select('name, countries(*)')
.eq('countries.name', 'Estonia')
# Data source
create table
countries (id int8 primary key, name text);
create table
cities (
id int8 primary key,
country_id int8 not null references countries,
name text
);
insert into
countries (id, name)
values
(1, 'Germany'),
(2, 'Indonesia');
insert into
cities (id, country_id, name)
values
(1, 2, 'Bali'),
(2, 1, 'Munich');
// Response
{
"data": [
{
"name": "Bali",
"countries": null
},
{
"name": "Munich",
"countries": null
}
],
"status": 200,
"statusText": "OK"
}
DB를 다룰 줄 모르고, SQL문도 잘 몰라서 처음에는 해석하는 것도 어려웠는데 내가 만든 테이블에 대입해 생각해보니 무슨 뜻인지 파악할 수 있었다.
const { data, error } = await supabase
.from("projects") // 데이터를 검색할 테이블
.select("profile_id, profiles(*)") // 데이터로 보여줄 부분
// profile_id는 각 프로젝트와 연결된 프로필 id
// profiles(*)는 profiles 테이블의 모든 열이 포함되어야 함
// 쉽게 생각하면, data 객체 안에 profile_id와 profiles가 출력
.eq("profiles.id", targetId); // 필터 적용
// profiles 테이블의 id 열이 targetId와 동일한 행만 검색
위와 같이 작성하면 아래와 같이 데이터를 가져온다. profiles.id가 targetId와 같은 걸 찾아서 profile_id와 project의 모든 열을 가져온다.
내가 가져오고 싶었던 데이터의 형태는 유저 프로필과 해당 유저의 project 열 모두였기 때문에 위는 내가 생각했던 데이터의 형태가 아니었다.
3. [결론] 전체 선택자를 사용하여 2개의 테이블 모두 한번에 가져오기
내가 원했던건 데이터의 일부가 아니라 profiles 테이블의 모든 열과 projects 테이블의 모든 열이었다. 전체 선택자를 사용하면 내가 원하는 형태로 데이터를 가져올 수 있었다.
const { data, error } = await supabase
.from("profiles")
.select("*, projects(*)")
.eq("id", targetId);
위와같이 projects 테이블의 전체 열이 profiles 테이블 안에 들어간 것을 확인할 수 있다.
이렇게 하면 한 번의 네트워크 요청으로 필요한 데이터를 모두 가져올 수 있으니 이전보다는 더 효율적으로 코드를 작성할 수 있을 것 같다.
💬
백엔드와 DB에 대해 거의 무지한 상태였기 때문에 테이블을 이런식으로 가져올 수 있을거라는 생각 자체를 처음에는 하지 못했다. 그런데 이전 팀 프로젝트에서 백엔드 팀원분들이 "테이블 간의 관계를 형성한다"라는 이야기를 몇차례 했던 걸 들은 적이 있었고, 아무것도 모르지만 테이블 관계도(?)도 본 적이 있었다. 그 때의 기억을 되살려보니 내가 원했던 걸 어떠한 형식으로 구현할 수 있을지 감을 잡았던 것 같고, supabase에서도 분명 이와 같은 기능을 제공할 것이라고 생각이 들었다. supabase를 사용하면서 프론트, 백을 선을 그어버리듯 나누어 학습하기보다는 좀 더 폭넓게 이해할 수 있도록 공부해야겠다는 생각이 들었다.
'Frontend Dev > Supabase' 카테고리의 다른 글
[supabase] supabase에서 유저 정보를 가져오는 방법 (getSession, getUser) (1) | 2024.07.17 |
---|---|
supabase auth와 나의 public 테이블 연동하기 (회원가입시 auth의 유저 정보를 public 테이블로 가져오는 방법) (1) | 2024.07.04 |