5
4

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

TypeScriptでSupabaseのテーブルからリレーションを使ってデータを取得する

Posted at

はじめに

TypeScriptでリレーションを使用してSupabaseのテーブルからデータを取得する方法についてまとめました。

リレーションとは、データベース内の複数のテーブル間で関係を構築することを指します。これにより、複数のテーブルから関連データを一度に取得しやすくなります。

この記事では、1対1、1対多、多対多のリレーションを設定し、実際にデータを取得する手順を例を交えて紹介します。

SupabaseはPostgreSQLをベースにしているため、リレーション機能をサポートしています。これにより、データの結合や集約が容易に行え、効率的なデータ操作が可能になります。

今回使用するテーブル構成

• users テーブル
	• id
	• username
	• profile_id
• profiles テーブル
	• id
	• name
• posts テーブル
	• id
	• user_id
	• title
• user_roles テーブル
	• user_id
	• role_id
•	roles テーブル
	• id
	• role_name

外部キーを設定する

Supabaseでリレーションを設定するには、データベーステーブルの定義において適切な外部キー(foreign key)制約を追加する必要があります。

以下のようにusersテーブルにprofile_idカラムを追加し、これをprofilesテーブルのidカラムに関連付けることで、リレーションを貼ることができます。

CREATE TABLE users (
  id SERIAL PRIMARY KEY,
  username VARCHAR(255)
);

CREATE TABLE posts (
  id SERIAL PRIMARY KEY,
  title VARCHAR(255),
  user_id INTEGER,
  FOREIGN KEY (user_id) REFERENCES users (id)
);

こんな感じで、他のテーブルにも外部キーを貼っていきます。

実際にリレーションを使ってデータを取得する

1対1のリレーション

users と profiles のリレーションを取得する例です。

const { data, error } = await supabase
  .from('users')
  .select(`
    id,
    username,
    profiles (
      id,
      name
    )
  `)

if (error) {
  console.error('Error fetching users with profiles:', error)
} else {
  console.log('Users with profiles:', data)
}

レスポンス例

[
  {
    "id": 1,
    "username": "user1",
    "profiles": {
      "id": 1,
      "name": "Profile 1"
    }
  },
  {
    "id": 2,
    "username": "user2",
    "profiles": {
      "id": 2,
      "name": "Profile 2"
    }
  }
]

1対多のリレーション

users と posts のリレーションを取得する例です。

const { data, error } = await supabase
  .from('users')
  .select(`
    id,
    username,
    posts (
      id,
      title
    )
  `)

if (error) {
  console.error('Error fetching users with posts:', error)
} else {
  console.log('Users with posts:', data)
}

レスポンス例

[
  {
    "id": 1,
    "username": "user1",
    "posts": [
      {
        "id": 1,
        "title": "Post 1"
      },
      {
        "id": 2,
        "title": "Post 2"
      }
    ]
  },
  {
    "id": 2,
    "username": "user2",
    "posts": [
      {
        "id": 3,
        "title": "Post 3"
      }
    ]
  }
]

多対多のリレーション

users と roles の多対多のリレーションを user_roles テーブルを通じて取得する例です。

const { data, error } = await supabase
  .from('users')
  .select(`
    id,
    username,
    user_roles (
      roles (
        id,
        role_name
      )
    )
  `)

if (error) {
  console.error('Error fetching users with roles:', error)
} else {
  console.log('Users with roles:', data)
}

レスポンス例

[
  {
    "id": 1,
    "username": "user1",
    "user_roles": [
      {
        "roles": {
          "id": 1,
          "role_name": "Admin"
        }
      },
      {
        "roles": {
          "id": 2,
          "role_name": "User"
        }
      }
    ]
  },
  {
    "id": 2,
    "username": "user2",
    "user_roles": [
      {
        "roles": {
          "id": 2,
          "role_name": "User"
        }
      }
    ]
  }
]

複数のリレーションの組み合わせ

複数のリレーションを組み合わせてデータを取得することも可能で、users、profiles、postsを同時に取得する場合は以下のようになります。

const { data, error } = await supabase
  .from('users')
  .select(`
    id,
    username,
    profiles (
      id,
      name
    ),
    posts (
      id,
      title
    )
  `)

if (error) {
  console.error('Error fetching users with profiles and posts:', error)
} else {
  console.log('Users with profiles and posts:', data)
}

レスポンス例

[
  {
    "id": 1,
    "username": "user1",
    "profiles": {
      "id": 1,
      "name": "Profile 1"
    },
    "posts": [
      {
        "id": 1,
        "title": "Post 1"
      },
      {
        "id": 2,
        "title": "Post 2"
      }
    ]
  },
  {
    "id": 2,
    "username": "user2",
    "profiles": {
      "id": 2,
      "name": "Profile 2"
    },
    "posts": [
      {
        "id": 3,
        "title": "Post 3"
      }
    ]
  }
]

INNER JOINとLEFT JOINで取得する場合

SupabaseはPostgreSQLを基盤としているため、PostgreSQLでサポートされているJOINの種類を利用できます。

INNER JOIN

INNER JOINは、両方のテーブルに共通するデータのみを取得します。

const { data, error } = await supabase
  .from('users')
  .select(`
    id,
    username,
    profiles!inner (
      id,
      name
    )
  `)

if (error) {
  console.error('Error fetching users with profiles:', error)
} else {
  console.log('Users with profiles:', data)
}

LEFT JOIN

LEFT JOINは、左側のテーブルのすべてのデータと、右側のテーブルに一致するデータを取得します。一致しない場合、右側のテーブルのデータはNULLになります。

const { data, error } = await supabase
  .from('users')
  .select(`
    id,
    username,
    profiles!left (
      id,
      name
    )
  `)

if (error) {
  console.error('Error fetching users with profiles:', error)
} else {
  console.log('Users with profiles:', data)
}

おわりに

リレーションを利用することで、複数のテーブルにまたがる複雑なデータを効率的に扱うことができます。

Supabaseの柔軟なクエリ機能を活用することで、INNER JOINやLEFT JOINなどの様々なJOINを使ってデータを取得することもできます。

TypeScriptとSupabaseを使ってリレーションを設定し、データを取得する方法について個人的な備忘録としても兼ねて紹介しました。

5
4
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
5
4

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?