建模和查詢多對多關係
問題
在關聯式資料庫中建模和查詢多對多關係可能具有挑戰性。本文展示了如何使用 Prisma ORM 來處理這個問題的兩個範例。第一個範例使用隱式多對多關係,第二個範例使用顯式多對多關係。
解決方案
隱式關係
這是一種多對多關係類型,其中 Prisma ORM 在內部處理關係表。隱式多對多關係的基本範例看起來像這樣
model Post {
id Int @id @default(autoincrement())
title String
tags Tag[]
}
model Tag {
id Int @id @default(autoincrement())
name String @unique
posts Post[]
}
若要建立文章及其標籤,可以使用 Prisma Client 撰寫如下程式碼
await prisma.post.create({
data: {
title: 'Types of relations',
tags: { create: [{ name: 'dev' }, { name: 'prisma' }] },
},
})
在上面的範例中,我們可以如下直接查詢文章及其標籤
await prisma.post.findMany({
include: { tags: true },
})
獲得的回應將會是
[
{
"id": 1,
"title": "Types of relations",
"tags": [
{
"id": 1,
"name": "dev"
},
{
"id": 2,
"name": "prisma"
}
]
}
]
另一個用例是,如果您想要新增標籤以及將現有標籤連接到文章。此範例適用於使用者為其文章建立新標籤,並且也選取了要新增的現有標籤。在這種情況下,我們可以透過以下方式執行此操作
await prisma.post.update({
where: { id: 1 },
data: {
title: 'Prisma is awesome!',
tags: { set: [{ id: 1 }, { id: 2 }], create: { name: 'typescript' } },
},
})
顯式關係
在您需要在關係表中儲存額外欄位,或者您正在內省已設定多對多關係的現有資料庫的情況下,大多需要建立顯式關係。這與上面使用的 schema 相同,但具有顯式關係表
model Post {
id Int @id @default(autoincrement())
title String
tags PostTags[]
}
model PostTags {
id Int @id @default(autoincrement())
post Post? @relation(fields: [postId], references: [id])
tag Tag? @relation(fields: [tagId], references: [id])
postId Int?
tagId Int?
@@index([postId, tagId])
}
model Tag {
id Int @id @default(autoincrement())
name String @unique
posts PostTags[]
}
將標籤新增至文章將會在關係表 (PostTags
) 以及標籤表 (Tag
) 中建立
await prisma.post.create({
data: {
title: 'Types of relations',
tags: {
create: [
{ tag: { create: { name: 'dev' } } },
{ tag: { create: { name: 'prisma' } } },
],
},
},
})
此外,查詢文章及其標籤將需要額外的 include
,如下所示
await prisma.post.findMany({
include: { tags: { include: { tag: true } } },
})
這將提供以下輸出
[
{
"id": 1,
"title": "Types of relations",
"tags": [
{
"id": 1,
"postId": 1,
"tagId": 1,
"tag": {
"id": 1,
"name": "prisma"
}
},
{
"id": 2,
"postId": 1,
"tagId": 2,
"tag": {
"id": 2,
"name": "dev"
}
}
]
}
]
有時,在您的 UI 中顯示關係表的資料並不理想。在這種情況下,最好的方法是在伺服器本身上擷取資料後對資料進行映射,並將該回應傳送到前端。
const result = posts.map((post) => {
return { ...post, tags: post.tags.map((tag) => tag.tag) }
})
這將提供與您透過隱式關係收到的輸出相似的輸出。
[
{
"id": 1,
"title": "Types of relations",
"tags": [
{
"id": 1,
"name": "prisma"
},
{
"id": 2,
"name": "dev"
}
]
}
]
本文說明了如何實作隱式和顯式多對多關係,以及如何使用 Prisma Client 查詢它們。