Drizzleのrelations機能の基本

Drizzleのrelations機能の基本

Drizzle ORM

最近Drizzle ORMを初めて使ったので、その時に簡単に公式ドキュメントをみて覚えておこーっとおもって書いている記事です

Drizzle ORM - Get started

主な特徴

SQL-likeとRelational、両方のAPIを提供

Drizzleは開発者のニーズに応じて2つの異なるアプローチでデータアクセスができる

SQL-like API

// SQLに慣れている人にとって直感的
await db
  .select()
  .from(users)
  .leftJoin(posts, eq(posts.userId, users.id))
  .where(eq(users.active, true))

Relational API

// ネストしたデータを簡単に取得
const result = await db.query.users.findMany({
  with: {
    posts: true,
    profile: true
  }
});

Relational APIでも常に1つのSQLクエリを生成するため、N+1問題を回避し高いパフォーマンスを維持するみたい。

学習コストがかなり低そう

SQLを知っていれば、Drizzleを知っているって言えるみたいで以下のようにほぼ同じじゃんってなる

-- 従来のSQL
SELECT * FROM users WHERE active = true ORDER BY name

// Drizzleでもほぼ同じ構造
db.select().from(users).where(eq(users.active, true)).orderBy(users.name)

Relationsとは

Drizzle ORMのrelations機能は、外部キー制約を追加するのとはちがうぽい

この辺実際にテーブルつくって試したかたちなので間違えてたら指摘してください🙏

外部キー制約(Foreign Keys)

  • データベースレベルの制約
  • データ整合性を保証
  • 制約違反時にエラー

Relations

  • アプリケーションレベルの抽象化
  • クエリAPIを使用可能にする
  • 構造的なデータ取得を実現する

重要ポイント クエリAPIを使いたい場合、Relations定義が必要で外部キー制約とは独立してる

// ❌ relationsなし → クエリAPIは使用不可
const result = await db.query.users.findMany({
  with: { posts: true } // Error
});

// ✅ relations定義あり → クエリAPI使用可能
export const usersRelations = relations(users, ({ many }) => ({
  posts: many(posts),
}));

選択肢の比較

選択肢1: SQL likeなやつ

const result = await db.select()
  .from(users)
  .leftJoin(posts, eq(posts.authorId, users.id));

// 結果:平坦で重複あり
[
  { userId: 1, userName: "田中", postId: 1, postTitle: "投稿1" },
  { userId: 1, userName: "田中", postId: 2, postTitle: "投稿2" },
]

選択肢2: Relations使用(relations定義が必要)

const result = await db.query.users.findMany({
  with: { posts: true }
});

// 結果:ネスト構造で重複なし
[
  {
    id: 1,
    name: "田中",
    posts: [
      { id: 1, title: "投稿1" },
      { id: 2, title: "投稿2" }
    ]
  }
]

Relations定義例


// テーブル定義
export const users = pgTable('users', {
  id: serial('id').primaryKey(),
  name: text('name'),
});

export const posts = pgTable('posts', {
  id: serial('id').primaryKey(),
  content: text('content'),
  authorId: integer('author_id'), // 外部キー制約は任意
});

// Relations定義(クエリAPIを使いたい場合)
export const usersRelations = relations(users, ({ many }) => ({
  posts: many(posts),
}));

export const postsRelations = relations(posts, ({ one }) => ({
  author: one(users, {
    fields: [posts.authorId],
    references: [users.id],
  }),
}));

簡単なまとめ

  • Relations = クエリAPIを使用可能にする設定
  • 外部キー制約は任意、Relationsはクエリapi使用時に必要
  • 従来のJOINかRelationsか、用途に応じて選択可能

Relationsと外部キーの違いをちゃんと理解してないとこまりそうなので、この記事が参考になれば幸いです!

記事を書いた人

Tsukamura

エンジニア

Tsukamura

株式会社Anycloudでエンジニアをしています。