Drizzleのrelations機能の基本
公開日2025.09.26

主な特徴
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と外部キーの違いをちゃんと理解してないとこまりそうなので、この記事が参考になれば幸いです!
Anycloudでは一緒に働くメンバーを募集しています!
Anycloudは、ユーザーの心を動かす体験を届けることを大切にしています。フルリモート・フルフレックスの環境のもと、ライフスタイルに合わせた働き方を実現しながら挑戦したい方を歓迎します。詳細はこちらをご覧ください。

