prisma 多対多をjoinして検索

過去に少しハマったので、備忘録として残しておきます。

prisma is 何 ?

TypeScriptのORMです。

公式はこちら
https://www.prisma.io/

構成

例えばeラーニングの様なサイトを作っているとします。

システムには受講者と講座が必要なので、それぞれ受講者テーブル(User)と 講座テーブル(Course)を用意します。

Userテーブル

idnickname
1太郎
2花子

Courseテーブル

idname
1国語
2算数
3理科
4社会

UserOnCoursesテーブル

iduserIdcourseId
111
212
313
421
522
624

中間テーブルのUserOnCoursesを用意します。


受講者側から見ると
太郎くん→「国語」と「算数」と「理科」を受講します。
花子さん→「国語」と「算数」と「社会」を受講します。

講座側から見ると
国語→「太郎」くんと「花子」さんに受講されます。
算数→「太郎」くんと「花子」さんに受講されます。
理科→「太郎」くんに受講されます。
社会→「花子」さんに受講されます。

受講者は複数の講座(対多)を受講し、講座も複数のユーザー(対多)に受講されます。

よって「User」と「Course」が多対多の関係になっており、それを中間テーブル「UserOnCourses」によって関連づけられています。

schema.prismaは下記のようになっています。

// schema.prisma

model User {
  id Int @id @default(autoincrement())
  nickname String
  ・
  ・
  ・
  courses UserOnCourses[]
}

model Course {
  id Int @id @default(autoincrement())
  name String
  ・
  ・
  ・
  users UserOnCourses[]
}

model UserOnCourses {
  user User @relation(fields: [userId], references: [id])
  userId Int
  course Course @relation(fields: [courseId], references: [id])
  courseId Int
  @@id([userId, courseId])
}

やりたいこと

国語の受講者を全員取得したい

// TypeScript  

const users = await this.prisma.user.findMany({
    select: {
      id: true,
      /**
       * ・
       * ・
       * ・
       */
    },
    where: {
      courses: {
        some: {
          courseId: {
            equals: 1 // Courseテーブルの国語のid,
          },
        },
      },
    },
  })

これで、国語を受講している太郎くんと花子さんの二人が取得されます。

因みに実際に発行されるSQLはこんな感じ

SELECT
  u."id"
FROM 
  "User" AS u
WHERE (
  (u.id) IN (
    SELECT 
      u1."id" 
    FROM 
      "User" AS u1 
    INNER JOIN "UserOnCourses" AS uoc 
      ON (uoc."userId") = (u1."id") 
    WHERE (
      uoc."courseId" = 1 AND 
      u1."id" IS NOT NULL
    )
  ))
;

以上

お問い合わせ

サービスに関するご相談やご質問などこちらからお問い合わせください。

03-55107260

受付時間 10:00〜17:00