跳到主要內容

CRUD

本頁面說明如何使用您產生的 Prisma Client API 執行 CRUD 操作。CRUD 是一個縮寫,代表

請參閱 Prisma Client API 參考文件,以取得每個方法的詳細說明。

範例 Schema

所有範例均基於以下 Schema

展開以查看範例 Schema
datasource db {
provider = "postgresql"
url = env("DATABASE_URL")
}

generator client {
provider = "prisma-client-js"
}

model ExtendedProfile {
id Int @id @default(autoincrement())
biography String
user User @relation(fields: [userId], references: [id])
userId Int @unique
}

model User {
id Int @id @default(autoincrement())
name String?
email String @unique
profileViews Int @default(0)
role Role @default(USER)
coinflips Boolean[]
posts Post[]
profile ExtendedProfile?
}

model Post {
id Int @id @default(autoincrement())
title String
published Boolean @default(true)
author User @relation(fields: [authorId], references: [id])
authorId Int
comments Json?
views Int @default(0)
likes Int @default(0)
categories Category[]
}

model Category {
id Int @id @default(autoincrement())
name String @unique
posts Post[]
}

enum Role {
USER
ADMIN
}

對於關聯式資料庫,請使用 db push 命令將範例 Schema 推送到您自己的資料庫

npx prisma db push

對於 MongoDB,請確保您的資料具有統一的形狀,並符合 Prisma Schema 中定義的模型。

建立

建立單一記錄

以下查詢建立 (create()) 具有兩個欄位的單一使用者

const user = await prisma.user.create({
data: {
email: 'elsa@prisma.io',
name: 'Elsa Prisma',
},
})
顯示查詢結果

使用者的 id 是自動產生的,而您的 Schema 決定了哪些欄位是必填的

使用產生的類型建立單一記錄

以下範例產生相同的結果,但在 create() 查詢的上下文之外建立名為 userUserCreateInput 變數。在完成簡單的檢查(「此 create() 查詢中是否應包含文章?」)之後,user 變數會傳遞到查詢中

import { PrismaClient, Prisma } from '@prisma/client'

const prisma = new PrismaClient()

async function main() {
let includePosts: boolean = false
let user: Prisma.UserCreateInput

// Check if posts should be included in the query
if (includePosts) {
user = {
email: 'elsa@prisma.io',
name: 'Elsa Prisma',
posts: {
create: {
title: 'Include this post!',
},
},
}
} else {
user = {
email: 'elsa@prisma.io',
name: 'Elsa Prisma',
}
}

// Pass 'user' object into query
const createUser = await prisma.user.create({ data: user })
}

main()

有關使用產生的類型的更多資訊,請參閱:產生的類型

建立多個記錄

Prisma Client 在 2.20.0 及更高版本中,以 GA 功能形式支援大量插入。

以下 createMany() 查詢建立多個使用者,並跳過任何重複項(email 必須是唯一的)

const createMany = await prisma.user.createMany({
data: [
{ name: 'Bob', email: 'bob@prisma.io' },
{ name: 'Bobo', email: 'bob@prisma.io' }, // Duplicate unique key!
{ name: 'Yewande', email: 'yewande@prisma.io' },
{ name: 'Angelique', email: 'angelique@prisma.io' },
],
skipDuplicates: true, // Skip 'Bobo'
})
顯示查詢結果
{
count: 3
}
警告

請注意,使用 MongoDB、SQLServer 或 SQLite 時,不支援 skipDuplicates

createMany() 使用單一 INSERT INTO 陳述式和多個值,這通常比每個資料列使用單獨的 INSERT 更有效率

BEGIN
INSERT INTO "public"."User" ("id","name","email","profileViews","role","coinflips","testing","city","country") VALUES (DEFAULT,$1,$2,$3,$4,DEFAULT,DEFAULT,DEFAULT,$5), (DEFAULT,$6,$7,$8,$9,DEFAULT,DEFAULT,DEFAULT,$10), (DEFAULT,$11,$12,$13,$14,DEFAULT,DEFAULT,DEFAULT,$15), (DEFAULT,$16,$17,$18,$19,DEFAULT,DEFAULT,DEFAULT,$20) ON CONFLICT DO NOTHING
COMMIT
SELECT "public"."User"."country", "public"."User"."city", "public"."User"."email", SUM("public"."User"."profileViews"), COUNT(*) FROM "public"."User" WHERE 1=1 GROUP BY "public"."User"."country", "public"."User"."city", "public"."User"."email" HAVING AVG("public"."User"."profileViews") >= $1 ORDER BY "public"."User"."country" ASC OFFSET $2

注意$transaction 內的多個 create() 陳述式會導致多個 INSERT 陳述式。

以下影片示範如何使用 createMany()faker.js 來使用範例資料植入資料庫

請參閱使用關聯 > 巢狀寫入,以取得關於同時建立記錄和一個或多個關聯記錄的資訊。

建立並傳回多個記錄

資訊

此功能在 Prisma ORM 5.14.0 及更高版本中適用於 PostgreSQL、CockroachDB 和 SQLite。

您可以使用 createManyAndReturn() 來建立多個記錄並傳回結果物件。

const users = await prisma.user.createManyAndReturn({
data: [
{ name: 'Alice', email: 'alice@prisma.io' },
{ name: 'Bob', email: 'bob@prisma.io' },
],
})
顯示查詢結果
警告

使用 createManyAndReturn() 時,relationLoadStrategy: join 不可用。

讀取

依 ID 或唯一識別碼取得記錄

以下查詢依唯一識別碼或 ID 傳回單一記錄 (findUnique())

// By unique identifier
const user = await prisma.user.findUnique({
where: {
email: 'elsa@prisma.io',
},
})

// By ID
const user = await prisma.user.findUnique({
where: {
id: 99,
},
})

如果您使用 MongoDB 連接器,且您的底層 ID 類型為 ObjectId,則可以使用該 ObjectId 的字串表示形式

// By ID
const user = await prisma.user.findUnique({
where: {
id: '60d5922d00581b8f0062e3a8',
},
})

取得所有記錄

以下 findMany() 查詢傳回所有 User 記錄

const users = await prisma.user.findMany()

您也可以分頁顯示您的結果

取得符合特定條件的第一個記錄

以下 findFirst() 查詢傳回最近建立的使用者,且該使用者至少有一篇貼文的讚數超過 100 個

  1. 依遞減 ID(最大優先)排序使用者 - 最大的 ID 是最新的
  2. 傳回遞減排序中,至少有一篇貼文的讚數超過 100 個的第一個使用者
const findUser = await prisma.user.findFirst({
where: {
posts: {
some: {
likes: {
gt: 100,
},
},
},
},
orderBy: {
id: 'desc',
},
})

取得篩選後的記錄清單

Prisma Client 支援依記錄欄位和關聯記錄欄位進行篩選

依單一欄位值篩選

以下查詢傳回電子郵件結尾為 "prisma.io" 的所有 User 記錄

const users = await prisma.user.findMany({
where: {
email: {
endsWith: 'prisma.io',
},
},
})

依多個欄位值篩選

以下查詢結合了運算子,以傳回名稱以 E 開頭至少有 1 次個人資料瀏覽次數的管理員

const users = await prisma.user.findMany({
where: {
OR: [
{
name: {
startsWith: 'E',
},
},
{
AND: {
profileViews: {
gt: 0,
},
role: {
equals: 'ADMIN',
},
},
},
],
},
})

以下查詢傳回電子郵件結尾為 prisma.io 至少有一篇未發布的貼文 (some) 的使用者

const users = await prisma.user.findMany({
where: {
email: {
endsWith: 'prisma.io',
},
posts: {
some: {
published: false,
},
},
},
})

請參閱使用關聯,以取得關於依關聯欄位值篩選的更多範例。

選取欄位的子集

以下 findUnique() 查詢使用 select 傳回特定 User 記錄的 emailname 欄位

const user = await prisma.user.findUnique({
where: {
email: 'emma@prisma.io',
},
select: {
email: true,
name: true,
},
})
顯示查詢結果

有關包含關聯的更多資訊,請參閱

以下查詢使用巢狀 select 來傳回

  • 使用者的 email
  • 每篇貼文的 likes 欄位
const user = await prisma.user.findUnique({
where: {
email: 'emma@prisma.io',
},
select: {
email: true,
posts: {
select: {
likes: true,
},
},
},
})
顯示查詢結果

有關包含關聯的更多資訊,請參閱選取欄位並包含關聯

選取不同的欄位值

請參閱選取 distinct,以取得關於選取不同欄位值的資訊。

以下查詢傳回所有 ADMIN 使用者,並在結果中包含每個使用者的貼文

const users = await prisma.user.findMany({
where: {
role: 'ADMIN',
},
include: {
posts: true,
},
})
顯示查詢結果

有關包含關聯的更多資訊,請參閱選取欄位並包含關聯

包含篩選後的關聯清單

請參閱使用關聯,以了解如何結合 includewhere 以取得篩選後的關聯清單 - 例如,僅包含使用者已發布的貼文。

更新

更新單一記錄

以下查詢使用 update() 來依 email 尋找並更新單一 User 記錄

const updateUser = await prisma.user.update({
where: {
email: 'viola@prisma.io',
},
data: {
name: 'Viola the Magnificent',
},
})
顯示查詢結果

更新多個記錄

以下查詢使用 updateMany() 來更新所有包含 prisma.ioUser 記錄

const updateUsers = await prisma.user.updateMany({
where: {
email: {
contains: 'prisma.io',
},
},
data: {
role: 'ADMIN',
},
})
顯示查詢結果

更新並傳回多個記錄

資訊

此功能在 Prisma ORM 6.2.0 及更高版本中適用於 PostgreSQL、CockroachDB 和 SQLite。

您可以使用 updateManyAndReturn() 以更新多個記錄並傳回結果物件。

const users = await prisma.user.updateManyAndReturn({
where: {
email: {
contains: 'prisma.io',
}
},
data: {
role: 'ADMIN'
}
})
顯示查詢結果
警告

使用 updateManyAndReturn() 時,relationLoadStrategy: join 不可用。

更新建立記錄

以下查詢使用 upsert() 來更新具有特定電子郵件地址的 User 記錄,如果該 User 記錄不存在,則建立該記錄

const upsertUser = await prisma.user.upsert({
where: {
email: 'viola@prisma.io',
},
update: {
name: 'Viola the Magnificent',
},
create: {
email: 'viola@prisma.io',
name: 'Viola the Magnificent',
},
})
顯示查詢結果
資訊

從 4.6.0 版本開始,Prisma Client 會在可能的情況下使用資料庫原生 SQL 命令執行 upsert。了解更多

Prisma Client 沒有 findOrCreate() 查詢。您可以使用 upsert() 作為替代方案。若要使 upsert() 的行為類似於 findOrCreate() 方法,請為 upsert() 提供空的 update 參數。

警告

upsert() 用作 findOrCreate() 的替代方案的限制是,upsert()where 條件中僅接受唯一的模型欄位。因此,如果 where 條件包含非唯一欄位,則無法使用 upsert() 來模擬 findOrCreate()

更新數字欄位

使用原子數字運算根據其目前值更新數字欄位 - 例如,遞增或乘法。以下查詢將 viewslikes 欄位遞增 1

const updatePosts = await prisma.post.updateMany({
data: {
views: {
increment: 1,
},
likes: {
increment: 1,
},
},
})

請參閱使用關聯,以取得關於中斷連線 (disconnect) 和連線 (connect) 關聯記錄的資訊。

刪除

刪除單一記錄

以下查詢使用 delete() 來刪除單一 User 記錄

const deleteUser = await prisma.user.delete({
where: {
email: 'bert@prisma.io',
},
})

嘗試刪除具有一篇或多篇貼文的使用者會導致錯誤,因為每篇 Post 都需要作者 - 請參閱串聯刪除

刪除多個記錄

以下查詢使用 deleteMany() 來刪除 email 包含 prisma.io 的所有 User 記錄

const deleteUsers = await prisma.user.deleteMany({
where: {
email: {
contains: 'prisma.io',
},
},
})

嘗試刪除具有一篇或多篇貼文的使用者會導致錯誤,因為每篇 Post 都需要作者 - 請參閱串聯刪除

刪除所有記錄

以下查詢使用 deleteMany() 來刪除所有 User 記錄

const deleteUsers = await prisma.user.deleteMany({})

請注意,如果使用者有任何關聯記錄(例如貼文),此查詢將會失敗。在這種情況下,您需要先刪除關聯記錄

警告

2.26.0 及更高版本中,可以使用預覽功能 參考動作來執行串聯刪除。

以下查詢使用 delete() 來刪除單一 User 記錄

const deleteUser = await prisma.user.delete({
where: {
email: 'bert@prisma.io',
},
})

但是,範例 Schema 包含 PostUser 之間的必要關聯,這表示您無法刪除具有貼文的使用者

The change you are trying to make would violate the required relation 'PostToUser' between the `Post` and `User` models.

若要解決此錯誤,您可以

  • 使關聯成為選填

    model Post {
    id Int @id @default(autoincrement())
    author User? @relation(fields: [authorId], references: [id])
    authorId Int?
    author User @relation(fields: [authorId], references: [id])
    authorId Int
    }
  • 在刪除使用者之前,將貼文的作者變更為其他使用者。

  • 在交易中以兩個不同的查詢刪除使用者及其所有貼文(所有查詢都必須成功)

    const deletePosts = prisma.post.deleteMany({
    where: {
    authorId: 7,
    },
    })

    const deleteUser = prisma.user.delete({
    where: {
    id: 7,
    },
    })

    const transaction = await prisma.$transaction([deletePosts, deleteUser])

從所有表格中刪除所有記錄

有時您想要從所有表格中移除所有資料,但保留實際的表格。這在開發環境和測試期間特別有用。

以下說明如何使用 Prisma Client 和 Prisma Migrate 從所有表格中刪除所有記錄。

使用 deleteMany() 刪除所有資料

當您知道應刪除表格的順序時,可以使用 deleteMany 函數。這會在 $transaction 中同步執行,並且可以與所有類型的資料庫搭配使用。

const deletePosts = prisma.post.deleteMany()
const deleteProfile = prisma.profile.deleteMany()
const deleteUsers = prisma.user.deleteMany()

// The transaction runs synchronously so deleteUsers must run last.
await prisma.$transaction([deleteProfile, deletePosts, deleteUsers])

優點

  • 當您預先知道 Schema 的結構時,效果良好
  • 同步刪除每個表格的資料

缺點

  • 當使用關聯式資料庫時,此函數的擴展性不如使用更通用的解決方案,後者會查找並 TRUNCATE 您的表格,而與其關聯式約束無關。請注意,當使用 MongoDB 連接器時,此擴展性問題不適用。

注意$transaction 會對每個模型表格執行串聯刪除,因此必須依序呼叫它們。

使用原始 SQL / TRUNCATE 刪除所有資料

如果您可以輕鬆使用原始 SQL,則可以使用 $executeRawUnsafe 在表格上執行 TRUNCATE 查詢。

在以下範例中,第一個索引標籤顯示如何透過使用 $queryRaw 查找來在 Postgres 資料庫上執行 TRUNCATE,該查找會對表格進行映射,並在單一查詢中 TRUNCATE 所有表格。

第二個索引標籤顯示執行相同的功能,但使用 MySQL 資料庫。在此情況下,必須先移除約束,才能執行 TRUNCATE,然後在完成後再重新恢復。整個過程以 $transaction 形式執行

const tablenames = await prisma.$queryRaw<
Array<{ tablename: string }>
>`SELECT tablename FROM pg_tables WHERE schemaname='public'`

const tables = tablenames
.map(({ tablename }) => tablename)
.filter((name) => name !== '_prisma_migrations')
.map((name) => `"public"."${name}"`)
.join(', ')

try {
await prisma.$executeRawUnsafe(`TRUNCATE TABLE ${tables} CASCADE;`)
} catch (error) {
console.log({ error })
}

優點

  • 可擴展
  • 非常快速

缺點

  • 無法復原操作
  • 當嘗試執行原始查詢時,使用保留的 SQL 關鍵字作為表格名稱可能會導致問題

使用 Prisma Migrate 刪除所有記錄

如果您使用 Prisma Migrate,則可以使用 migrate reset,這將會

  1. Drop 資料庫
  2. 建立新的資料庫
  3. 套用遷移
  4. 使用資料植入資料庫

進階查詢範例

建立深度巢狀的記錄樹狀結構

  • 單一 User
  • 兩個新的關聯 Post 記錄
  • 連線或建立每個貼文的 Category
const u = await prisma.user.create({
include: {
posts: {
include: {
categories: true,
},
},
},
data: {
email: 'emma@prisma.io',
posts: {
create: [
{
title: 'My first post',
categories: {
connectOrCreate: [
{
create: { name: 'Introductions' },
where: {
name: 'Introductions',
},
},
{
create: { name: 'Social' },
where: {
name: 'Social',
},
},
],
},
},
{
title: 'How to make cookies',
categories: {
connectOrCreate: [
{
create: { name: 'Social' },
where: {
name: 'Social',
},
},
{
create: { name: 'Cooking' },
where: {
name: 'Cooking',
},
},
],
},
},
],
},
},
})