今天要來繼續介紹 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.author
的 annotated relation field
,透過 Post.authorId(FK)
關聯 User.id(PK)
,簡單來說上面的 schema
代表:
user
可以有 0 個至多個 posts
post
並需要有一個 user
最多也只有一個 user
所以才會是一對多的關係
和一對一的關聯情況一樣,你可以指定其他的欄位當作你關聯的 id
,只要你能確保資料的唯一性,以 user
為例子,我們把 email
指定成為一的欄位,對應個字的 post
,調整 @relation
的 references
是 User.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
來說我們組合 firstName
跟 lastName
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
的情況,這樣才能代表 User
跟 Post
是一對多,如果 Post.authorId
加上 Unique
變成 "authorId" integer NOT NULL Unique
這樣 User
跟 Post
的關係就變成一對一了~
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
去定義他,一對一有,一對多沒有
上面說到以下面的例子來說一個 User
可以有 0
個至 N
個 Post
,Post
至少要有一個 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
中要如何在 prisma
filter
你要的 data
,簡單整理一下常用的 options
這邊我們會用 is
跟 isNot
去表示 relation
有沒有對應的內容,以下面的範例來說,我們想找尋 post.author
不是 Bob
這個人,同時他的 age
必須要大於 40
歲
const users = await prisma.post.findMany({
where: {
author: {
isNot: {
name: 'Bob',
},
is: {
age: {
gt: 40,
},
},
},
},
include: {
author: true,
},
})
-to-many
則有三個 some
、every
、none
用法跟 js
的 array 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,
},
})
這邊代表找到User
沒有 Post
的 Record
const usersWithZeroPosts = await prisma.user.findMany({
where: {
posts: {
none: {},
},
},
include: {
posts: true,
},
})
反過來因為 post
他是一對多的一那邊,所以可以直接用 null
去找尋沒有 user
的 post
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