iT邦幫忙

2024 iThome 鐵人賽

DAY 12
2
Modern Web

一些讓你看來很強的 ORM - prisma系列 第 12

Day12. 一些讓你看來很強的 ORM - prisma (relation)1-n

  • 分享至 

  • xImage
  •  

今天要來繼續介紹 relation one to many 以下簡稱一對多 ,一對多代表的意思是一個 model 可以關聯 0 到多個 model 所以他也可以是 optional 如下:

model User {
  id    Int    @id @default(autoincrement())
  posts Post[]
}

model Post {
  id       Int  @id @default(autoincrement())
  author   User @relation(fields: [authorId], references: [id])
  authorId Int
}

User.posts 代表著 Post.authorannotated relation field ,透過 Post.authorId(FK) 關聯 User.id(PK),簡單來說上面的 schema 代表:

  • 一個 user 可以有 0 個至多個 posts
  • 一個 post 並需要有一個 user 最多也只有一個 user

所以才會是一對多的關係

Relation Another Fields

和一對一的關聯情況一樣,你可以指定其他的欄位當作你關聯的 id ,只要你能確保資料的唯一性,以 user 為例子,我們把 email 指定成為一的欄位,對應個字的 post,調整 @relationreferencesUser.email,同時在 Post@relation.fileds 也調整一下 fileds name 改成 authorEmail ,這樣才知道我們的 post 是關聯到 User.email

model User {
  id    Int    @id @default(autoincrement())
  email String @unique // <-- add unique attribute
  posts Post[]
}

model Post {
  id          Int    @id @default(autoincrement())
  authorEmail String
  author      User   @relation(fields: [authorEmail], references: [email])
}

同樣你也可以組合成特殊的 id ,以 User 來說我們組合 firstNamelastName

model User {

  firstName String 
  lastName String
  posts Post[]

  @@id([firstName,lastName])
}

model Post {
  id          Int    @id @default(autoincrement())
  authorFirstName String // relation scalar field (used in the `@relation` attribute above)
  authorLastName  String // relation scalar field (used in the `@relation` attribute above)
  author      User   @relation(fields: [authorLastName,authorFirstName], references: [firstName,lastName])
}

原生 SQL 語法如下,這邊要注意 Post.authorId 並沒有加上 Unique 的情況,這樣才能代表 UserPost 是一對多,如果 Post.authorId 加上 Unique 變成 "authorId" integer NOT NULL Unique 這樣 UserPost 的關係就變成一對一了~

CREATE TABLE "User" (
    id SERIAL PRIMARY KEY
);
CREATE TABLE "Post" (
    id SERIAL PRIMARY KEY,
    "authorId" integer NOT NULL,
    FOREIGN KEY ("authorId") REFERENCES "User"(id)
);

簡單來說一對一跟一對多最大的差別在於 foreign key 有沒有 UNIQUE 去定義他,一對一有,一對多沒有

Optional one-to-many relation

上面說到以下面的例子來說一個 User 可以有 0 個至 NPostPost 至少要有一個 User 且最多一個,如果你希望 Post 也可以不用指定 user 的話在 @relation 的地方加上 ? 就可以

model User {
  id    Int    @id @default(autoincrement())
  posts Post[]
}

model Post {
  id       Int   @id @default(autoincrement())
  author   User? @relation(fields: [authorId], references: [id])
  authorId Int?
}

所以在沒有加上 ? 前,create 一個 post 必須指定哪一個 user

model User {
  id    Int    @id @default(autoincrement())
  posts Post[]
}

model Post {
  id       Int  @id @default(autoincrement())
  author   User @relation(fields: [authorId], references: [id])
  authorId Int
}

Relation filters

這邊補充一下 relation 中要如何在 prisma filter 你要的 data ,簡單整理一下常用的 options

Filter on "-to-one" relations

這邊我們會用 isisNot 去表示 relation 有沒有對應的內容,以下面的範例來說,我們想找尋 post.author 不是 Bob 這個人,同時他的 age 必須要大於 40

const users = await prisma.post.findMany({
  where: {
    author: {
      isNot: {
        name: 'Bob',
      },
      is: {
        age: {
          gt: 40,
        },
      },
    },
  },
  include: {
    author: true,
  },
})

Filter on "-to-many" relations

-to-many 則有三個 someeverynone 用法跟 jsarray method 一樣概念會是:

Requirement Query option to use
"I want a list of every User that has at least one unpublished Post record" some posts are unpublished
"I want a list of every User that has no unpublished Post records" none of the posts are unpublished
"I want a list of every User that has only unpublished Post records" every posts are unpublished

所以這邊我要找尋 user.post 他的 views 並沒有大於 100 同時他的 likes必須大於 50

const users = await prisma.user.findMany({
  where: {
    posts: {
      none: {
        views: {
          gt: 100,
        },
      },
      every: {
        likes: {
          lte: 50,
        },
      },
    },
  },
  include: {
    posts: true,
  },
})

Filter Absence Records

這邊代表找到User 沒有 PostRecord

const usersWithZeroPosts = await prisma.user.findMany({
  where: {
    posts: {
      none: {},
    },
  },
  include: {
    posts: true,
  },
})

反過來因為 post 他是一對多的一那邊,所以可以直接用 null 去找尋沒有 userpost

const postsWithNoAuthor = await prisma.post.findMany({
  where: {
    author: null, // or author: { }
  },
  include: {
    author: true,
  },
})

那如果要找到 User 至少會有一篇 post 的話則用 some

const usersWithSomePosts = await prisma.user.findMany({
  where: {
    posts: {
      some: {},
    },
  },
  include: {
    posts: true,
  },
})

大家如果有問題可以來小弟的群組討論~

✅ 前端社群 :
https://lihi3.cc/kBe0Y


上一篇
Day11. 一些讓你看來很強的 ORM - prisma (relation)1-1
下一篇
Day13. 一些讓你看來很強的 ORM - prisma (relation)m-n
系列文
一些讓你看來很強的 ORM - prisma30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言