☠️

SupabaseのJavaScript Client Libraryで多対多のリレーションを扱う(抽出/フィルタリング編)

2023/09/26に公開

はじめに

SupabaseのJavaScript Client Libraryを使って、多対多リレーションシップのデータを全件抽出したりフィルタリングする際に、知らないと躓きやすい作法をまとめました。

https://supabase.com/docs/reference/javascript/introduction

準備

検証用に、SupabaseのSQL Editorを使って三つのテーブルを用意します。

  • 記事テーブル
create table public.articles (
  id bigint generated by default as identity primary key,
  title text not null,
  slug text not null unique,
  content text not null
);
  • タグテーブル
create table public.tags (
  id bigint generated by default as identity primary key,
  name text not null unique
);
  • 中間テーブル
create table public.articles_tags (
  article_id bigint not null references public.articles on delete cascade,
  tag_id bigint not null references public.tags on delete cascade,
  
  primary key (article_id, tag_id)
);

記事データを全件抽出する

const { data: articles, error } = await supabase
  .from('articles')
  .select('title,slug,tags(name)');
  // 全フィールドを指定する場合は
  // .select('*,tags(name)');

特定のタグでフィルタリングして記事データを抽出する

以下の既述で抽出できそうですが、少し問題があります。
複数のタグと関連付けされている記事データが抽出された場合に、抽出条件のタグしか参照できなくなってしまいます。

例えば、「政治」「スポーツ」「エンタメ」のタグと関連付けされている記事データAがあったとします。
記事全件を「スポーツ」タグでフィルタリングした際に、抽出された記事データAのタグ情報が「スポーツ」だけになってしまうということです。

const tagName = 'abc';

const { data: articles, error } = await supabase
  .from('articles')
  .select('title,slug,tags(name)')
  .eq('tags.name', tagName);

これはSQLで処理した際と同じ挙動なので、以下のように対処できます。

const tagName = 'abc';

const { data: tag, error } = await supabase
  .from('tags')
  .select('articles(title,slug,tags(name))')
  .eq('name', tagName)
  .single();
  
const articles = tag.articles;

Discussion