跳至主要内容

Prisma Client API 参考

无需 Rust 二进制文件即可使用 Prisma ORM

如果 Prisma ORM 的 Rust 引擎二进制文件导致捆绑包大小过大、构建缓慢或部署问题(例如,在无服务器或边缘环境中),您可以在不使用它们的情况下使用它,只需配置您的 generator

generator client {
provider = "prisma-client"
output = "./generated"
engineType = "client"
}

无需 Rust 二进制文件的 Prisma ORM 已于 v6.16.0正式发布

请注意,在这种情况下您需要使用驱动适配器

使用此架构时

  • 不会下载或附带 Rust 查询引擎二进制文件。
  • 数据库连接池由您安装的原生 JS 数据库驱动程序维护(例如,PostgreSQL 的 @prisma/adapter-pg)。

此设置可以简化无服务器或边缘运行时的部署。在此处文档中了解更多信息。

好奇我们为什么放弃 Rust 引擎?请查看这篇博客文章,了解我们为何从 Rust 二进制引擎转向全 TypeScript 方法,以实现更快、更轻的 Prisma ORM。

Prisma Client API 参考文档基于以下 schema

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

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

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)
}

enum Role {
USER
ADMIN
}

所有示例生成的类型(如 UserSelectUserWhereUniqueInput)均基于 User 模型。

PrismaClient

本节描述了 PrismaClient 构造函数及其参数。

备注

  • 参数在运行时验证。

datasources

以编程方式覆盖 schema.prisma 文件中 datasource 块的属性 - 例如,作为集成测试的一部分。另请参阅:数据源

从版本 5.2.0 开始,您还可以使用 datasourceUrl 属性以编程方式覆盖数据库连接字符串。

属性

示例属性示例值描述
db{ url: 'file:./dev_qa.db' }数据库连接 URL

备注

  • 每次添加或重命名数据源时,都必须重新生成 Prisma Client。数据源名称包含在生成的客户端中。
  • 如果您在 schema 中将 datasource 块命名为其他名称,请将 db 替换为您 datasource 块的名称。

示例

以编程方式覆盖数据源 url
import { PrismaClient } from '../prisma/generated/client';

const prisma = new PrismaClient({
datasources: {
db: {
url: 'file:./dev_qa.db',
},
},
});

基于以下 datasource

datasource db {
provider = "sqlite"
}

datasourceUrl

以编程方式覆盖 schema.prisma 文件中的 datasource 块。

属性

选项示例值描述
数据库连接字符串'file:./dev_qa.db'数据库连接 URL

示例

import { PrismaClient } from '../prisma/generated/client';

const prisma = new PrismaClient({
datasourceUrl: 'postgresql://johndoe:randompassword@localhost:5432/mydb',
});

log

确定日志的类型和级别。另请参阅:日志

选项

选项示例
日志级别数组[ "info", "query" ]
日志定义数组[ { level: "info", emit: "event" }, { level: "warn", emit: "stdout" }]
日志级别
名称示例
query记录 Prisma 运行的所有查询。

对于关系型数据库,这会记录所有 SQL 查询。示例
prisma:query SELECT "public"."User"."id", "public"."User"."email" FROM "public"."User" WHERE ("public"."User"."id") IN (SELECT "t0"."id" FROM "public"."User" AS "t0" INNER JOIN "public"."Post" AS "j0" ON ("j0"."authorId") = ("t0"."id") WHERE ("j0"."views" > $1 AND "t0"."id" IS NOT NULL)) OFFSET $2

对于 MongoDB,这会使用 mongosh shell 格式记录查询。示例
prisma:query db.User.deleteMany({ _id: ( $in: [ “6221ce49f756b0721fc00542”, ], }, })
info示例
prisma:info Started http server on http://127.0.0.1:58471
warn警告。
error错误。
发出格式
名称描述
stdout请参阅:stdout
event引发您可以订阅的事件。
事件类型

query 事件类型

index.d.ts
export type QueryEvent = {
timestamp: Date;
query: string; // Query sent to the database
params: string; // Query parameters
duration: number; // Time elapsed (in milliseconds) between client issuing query and database responding - not only time taken to run query
target: string;
};

请注意,对于 MongoDB,paramsduration 字段将为 undefined。

所有其他日志级别事件类型

index.d.ts
export type LogEvent = {
timestamp: Date;
message: string;
target: string;
};

示例

queryinfo 记录到 stdout
import { PrismaClient } from '../prisma/generated/client';

const prisma = new PrismaClient({ log: ['query', 'info'] });

async function main() {
const countUsers = await prisma.user.count({});
}

main()
.then(async () => {
await prisma.$disconnect();
})
.catch(async (e) => {
console.error(e);
await prisma.$disconnect();
process.exit(1);
});
显示CLI结果
query 事件记录到控制台
import { PrismaClient } from '../prisma/generated/client';

const prisma = new PrismaClient({
log: [{ level: 'query', emit: 'event' }],
});

prisma.$on('query', (e) => {
console.log(e);
});

async function main() {
const countUsers = await prisma.user.count({});
}

main()
.then(async () => {
await prisma.$disconnect();
})
.catch(async (e) => {
console.error(e);
await prisma.$disconnect();
process.exit(1);
});
显示CLI结果
infowarnerror 事件记录到控制台
import { PrismaClient } from '../prisma/generated/client';

const prisma = new PrismaClient({
log: [
{ level: 'warn', emit: 'event' },
{ level: 'info', emit: 'event' },
{ level: 'error', emit: 'event' },
],
});

prisma.$on('warn', (e) => {
console.log(e);
});

prisma.$on('info', (e) => {
console.log(e);
});

prisma.$on('error', (e) => {
console.log(e);
});

async function main() {
const countUsers = await prisma.user.count({});
}

main()
.then(async () => {
await prisma.$disconnect();
})
.catch(async (e) => {
console.error(e);
await prisma.$disconnect();
process.exit(1);
});
显示CLI结果

errorFormat

确定 Prisma Client 返回的错误的级别和格式。

错误格式

名称描述
undefined如果未定义,则默认值为无色。
pretty启用漂亮的错误格式。
colorless(默认)启用无色错误格式。
minimal启用最小错误格式。

示例

无错误格式
const prisma = new PrismaClient({
// Defaults to colorless
});
pretty 错误格式
const prisma = new PrismaClient({
errorFormat: 'pretty',
});
colorless 错误格式
const prisma = new PrismaClient({
errorFormat: 'colorless',
});
minimal 错误格式
const prisma = new PrismaClient({
errorFormat: 'minimal',
});

adapter

定义驱动适配器的实例。另请参阅数据库驱动

信息

从 5.4.0 版本开始,此功能作为预览功能提供,受 driverAdapters 功能标志控制。自 6.16.0 起已普遍可用。

示例

以下示例使用 Neon 驱动适配器

import { PrismaNeon } from '@prisma/adapter-neon';
import { PrismaClient } from '../prisma/generated/client';
import dotenv from 'dotenv';

dotenv.config();
const connectionString = `${process.env.DATABASE_URL}`;

const adapter = new PrismaNeon({ connectionString });
const prisma = new PrismaClient({ adapter });

rejectOnNotFound

信息

rejectOnNotFound 已在 v5.0.0 中移除。

已弃用:rejectOnNotFound 在 v4.0.0 中已弃用。从 v4.0.0 开始,使用查询 findUniqueOrThrowfindFirstOrThrow

使用 rejectOnNotFound 参数配置 findUnique() 和/或 findFirst,以便在未找到记录时抛出错误。默认情况下,如果未找到记录,这两个操作都返回 null

备注

选项

选项描述
RejectOnNotFound全局启用(true / false抛出自定义错误。
RejectPerOperation每个操作启用(true / false每个模型每个操作抛出自定义错误。

示例

findUnique()findFirst 全局启用
const prisma = new PrismaClient({
rejectOnNotFound: true,
});
为特定操作全局启用
const prisma = new PrismaClient({
rejectOnNotFound: {
findUnique: true,
},
});
如果未找到记录,则按模型和操作抛出自定义错误
const prisma = new PrismaClient({
rejectOnNotFound: {
findFirst: {
User: (err) => new Error('User error'),
Post: (err) => new Error('Post error!'),
},
findUnique: {
User: (err) => new Error('User error'),
Post: (err) => new Error('Post error!'),
},
},
});

transactionOptions

信息

transactionOptions 在 v5.10.0 中引入。

允许在构造函数级别全局设置事务选项

备注

  • 事务级别可以在每个事务级别覆盖。

选项

选项描述
maxWaitPrisma Client 等待从数据库获取事务的最长时间。默认值为 2 秒。
timeout交互式事务在被取消和回滚之前可以运行的最长时间。默认值为 5 秒。
isolationLevel设置事务隔离级别。默认情况下,这设置为数据库中当前配置的值。可用值可能因您使用的数据库而异。

示例

const prisma = new PrismaClient({
transactionOptions: {
isolationLevel: Prisma.TransactionIsolationLevel.Serializable,
maxWait: 5000, // default: 2000
timeout: 10000, // default: 5000
},
});

模型查询

使用模型查询对模型执行 CRUD 操作。另请参阅:CRUD

注意:最佳实践是始终在将不受信任的用户数据传递给 Prisma 查询之前对其进行验证和清理。如果不这样做,如果绕过类型检查,可能会导致 SQL 注入或其他注入漏洞。确保用户提供的值不会无意中绕过关键检查。我们强烈建议在应用程序层执行类型检查和输入验证。有关更多详细信息,请参阅自定义验证部分。

findUnique()

findUnique() 查询允许您检索单个数据库记录

  • ID
  • 唯一 属性

findUnique() 在版本 2.12.0 中替换了 findOne

备注

选项

名称示例类型(User必需描述
whereUserWhereUniqueInput包装模型的所有字段,以便可以选择记录(了解更多)。
在 4.5.0 版本之前,此类型仅包装模型的唯一字段。
selectXOR<UserSelect, null>指定要在返回对象上包含的属性
includeXOR<UserInclude, null>指定要在返回对象上急切加载的关系
omitXOR<UserOmit, null>指定要在返回对象上排除的属性。自 5.13.0 起处于预览状态
relationLoadStrategy'join''query'默认值:join。指定关系查询的加载策略。仅与 include(或关系字段上的 select)结合使用。自 5.9.0 起处于预览状态。

返回类型

返回类型示例描述
JavaScript 对象(类型化)User
JavaScript 对象(普通){ title: "Hello world" }使用 selectinclude 确定要返回的字段。
nullnull未找到记录

示例

获取 id42User 记录
const result = await prisma.user.findUnique({
where: {
id: 42,
},
});
获取 emailalice@prisma.ioUser 记录
const result = await prisma.user.findUnique({
where: {
email: 'alice@prisma.io',
},
});
获取 firstNameAlicelastNameSmithUser 记录(@@unique
展开示例 User 模型,其中包含 @@unique 块
model User {
firstName String
lastName String

@@unique(fields: [firstName, lastName], name: "fullname")
}
const result = await prisma.user.findUnique({
where: {
fullname: {
// name property of @@unique attribute - default is firstname_lastname
firstName: 'Alice',
lastName: 'Smith',
},
},
});
获取 firstNameAlicelastNameSmithUser 记录(@@id
展开示例 User 模型,其中包含 @@id 块
model User {
firstName String
lastName String

@@id([firstName, lastName])
}
const result = await prisma.user.findUnique({
where: {
firstName_lastName: {
firstName: 'Alice',
lastName: 'Smith',
},
},
});

findUniqueOrThrow()

findUniqueOrThrow() 以与 findUnique() 相同的方式检索单个记录。但是,如果查询未找到请求的记录,它将抛出 PrismaClientKnownRequestError

请注意,在 Prisma v6 之前,它会抛出 NotFoundError: No User found error

以下是其用法示例

await prisma.user.findUniqueOrThrow({
where: { id: 1 },
});

findUniqueOrThrow()findUnique() 的区别如下

  • 其返回类型不可为空。例如,post.findUnique() 可以返回 postnull,但 post.findUniqueOrThrow() 总是返回 post

  • 它与 $transaction API 中的顺序操作不兼容。如果查询抛出 PrismaClientKnownRequestError,则 API 不会回滚调用数组中的任何操作。作为一种解决方法,您可以按如下方式使用带有 $transaction API 的交互式事务

     $transaction(async (prisma) => {
    await prisma.model.create({ data: { ... });
    await prisma.model.findUniqueOrThrow();
    })

findFirst()

findFirst 返回列表中符合您条件的第一个记录。

备注

  • 如果您希望在未找到记录时查询抛出错误,请考虑改用findFirstOrThrow

选项

名称示例类型(User必需描述
selectXOR<UserSelect, null>指定要在返回对象上包含的属性
includeXOR<UserInclude, null>指定要在返回对象上急切加载的关系
omitXOR<UserOmit, null>指定要在返回对象上排除的属性。自 5.13.0 起处于预览状态。
relationLoadStrategy'join''query'默认值:join。指定关系查询的加载策略。仅与 include(或关系字段上的 select)结合使用。自 5.9.0 起处于预览状态。
whereUserWhereInput所有模型字段包装在一个类型中,以便可以按任何属性筛选列表。
orderByXOR<Enumerable<UserOrderByInput>, UserOrderByInput>允许您按任何属性排序返回的列表。

返回类型

返回类型示例描述
JavaScript 对象(类型化)User指定要在返回对象上包含的属性。
JavaScript 对象(普通){ title: "Hello world" }使用 selectinclude 确定要返回的字段。
nullnull未找到记录

备注

  • findFirst 在底层调用 findMany 并接受相同的查询选项。
  • 在使用 findFirst 查询时传入负 take 值会反转列表的顺序。

示例

请参阅筛选条件和运算符,了解如何筛选结果的示例。

获取 nameAlice 的第一个 User 记录
const user = await prisma.user.findFirst({
where: { name: 'Alice' },
});
获取 titleA test 开头的第一个 Post 记录,使用 take 反转列表
import { PrismaClient } from '../prisma/generated/client';

const prisma = new PrismaClient({});

async function main() {
const a = await prisma.post.create({
data: {
title: 'A test 1',
},
});

const b = await prisma.post.create({
data: {
title: 'A test 2',
},
});

const c = await prisma.post.findFirst({
where: {
title: {
startsWith: 'A test',
},
},
orderBy: {
title: 'asc',
},
take: -1, // Reverse the list
});
}

main();

findFirstOrThrow()

findFirstOrThrow() 以与 findFirst() 相同的方式检索单个数据记录。但是,如果查询未找到记录,它将抛出 PrismaClientKnownRequestError

请注意,在 Prisma v6 之前,它会抛出 NotFoundError: No User found error

findFirstOrThrow()findFirst() 的区别如下

  • 其返回类型不可为空。例如,post.findFirst() 可以返回 postnull,但 post.findFirstOrThrow 总是返回 post

  • 它与 $transaction API 中的顺序操作不兼容。如果查询返回 PrismaClientKnownRequestError,则 API 不会回滚调用数组中的任何操作。作为一种解决方法,您可以按如下方式使用带有 $transaction API 的交互式事务

    prisma.$transaction(async (tx) => {
    await tx.model.create({ data: { ... });
    await tx.model.findFirstOrThrow();
    })

findMany()

findMany 返回记录列表。

选项

名称类型必需描述
selectXOR<PostSelect, null>指定要在返回对象上包含的属性
includeXOR<PostInclude, null>指定要在返回对象上急切加载的关系
omitXOR<PostOmit, null>指定要在返回对象上排除的属性。自 5.13.0 起处于预览状态
relationLoadStrategy'join''query'默认值:join。指定关系查询的加载策略。仅与 include(或关系字段上的 select)结合使用。自 5.9.0 起处于预览状态。
whereUserWhereInput所有模型字段包装在一个类型中,以便可以按任何属性筛选列表。
orderByXOR<Enumerable<PostOrder
ByInput>, PostOrderByInput>
允许您按任何属性排序返回的列表。
cursorUserWhereUniqueInput指定列表的位置(值通常指定 id 或另一个唯一值)。
takenumber指定列表中应返回的对象数量(从列表的开头(正值)或结尾(负值)从提及的 cursor 位置看)
skipnumber指定列表中应跳过的返回对象数量。
distinctEnumerable<UserDistinctFieldEnum>允许您按特定字段筛选掉重复行 - 例如,仅返回不同的 Post 标题。

返回类型

返回类型示例描述
JavaScript 数组对象(类型化)User[]
JavaScript 数组对象(普通)[{ title: "Hello world" }]使用 selectinclude 确定要返回的字段。
空数组[]未找到匹配记录。

示例

请参阅筛选条件和运算符,了解如何筛选结果的示例。

获取所有 nameAliceUser 记录
const user = await prisma.user.findMany({
where: { name: 'Alice' },
});

create()

create 创建新的数据库记录。

选项

名称类型必需描述
dataXOR<UserCreateInput,
UserUncheckedCreateInput>
将所有模型字段包装在一个类型中,以便在创建新记录时提供。它还包括关系字段,允许您执行(事务性)嵌套插入。在数据模型中标记为可选或具有默认值的字段是可选的。
selectXOR<UserSelect, null>指定要在返回对象上包含的属性
includeXOR<UserInclude, null>指定要在返回对象上急切加载的关系
omitXOR<UserOmit, null>指定要在返回对象上排除的属性。自 5.13.0 起处于预览状态
relationLoadStrategy'join''query'默认值:join。指定关系查询的加载策略。仅与 include(或关系字段上的 select)结合使用。自 5.9.0 起处于预览状态。

返回类型

返回类型示例描述
JavaScript 对象(类型化)User
JavaScript 对象(普通){ name: "Alice Wonderland" }使用 selectinclude 确定要返回的字段。

备注

  • 您还可以执行嵌套create - 例如,同时添加一个 User 和两个 Post 记录。

示例

创建一个仅具有必需字段 email 的新记录
const user = await prisma.user.create({
data: { email: 'alice@prisma.io' },
});
创建多个新记录

在大多数情况下,您可以使用createMany()createManyAndReturn() 查询执行批量插入。但是,在某些情况下,create() 是插入多个记录的最佳选项

以下示例导致两个 INSERT 语句

import { Prisma, PrismaClient } from '../prisma/generated/client';

const prisma = new PrismaClient({ log: ['query'] });

async function main() {
let users: Prisma.UserCreateInput[] = [
{
email: 'ariana@prisma.io',
name: 'Ari',
profileViews: 20,
coinflips: [true, false, false],
role: 'ADMIN',
},
{
email: 'elsa@prisma.io',
name: 'Elsa',
profileViews: 20,
coinflips: [true, false, false],
role: 'ADMIN',
},
];

await Promise.all(
users.map(async (user) => {
await prisma.user.create({
data: user,
});
})
);
}

main()
.then(async () => {
await prisma.$disconnect();
})
.catch(async (e) => {
console.error(e);
await prisma.$disconnect();
process.exit(1);
});
显示CLI结果
prisma:query BEGIN
prisma:query INSERT INTO "public"."User" ("name","email","profileViews","role","coinflips") VALUES ($1,$2,$3,$4,$5) RETURNING "public"."User"."id"
prisma:query SELECT "public"."User"."id", "public"."User"."name", "public"."User"."email", "public"."User"."profileViews", "public"."User"."role", "public"."User"."coinflips" FROM "public"."User" WHERE "public"."User"."id" = $1 LIMIT $2 OFFSET $3
prisma:query INSERT INTO "public"."User" ("name","email","profileViews","role","coinflips") VALUES ($1,$2,$3,$4,$5) RETURNING "public"."User"."id"
prisma:query COMMIT
prisma:query SELECT "public"."User"."id", "public"."User"."name", "public"."User"."email", "public"."User"."profileViews", "public"."User"."role", "public"."User"."coinflips" FROM "public"."User" WHERE "public"."User"."id" = $1 LIMIT $2 OFFSET $3
prisma:query COMMIT

update()

update 更新现有数据库记录。

选项

名称类型必需描述
dataXOR<UserUpdateInput
UserUncheckedUpdateInput>
将模型的所有字段包装在一个类型中,以便在更新现有记录时提供。在数据模型中标记为可选或具有默认值的字段是可选的。
whereUserWhereUniqueInput包装模型的所有字段,以便可以选择记录(了解更多)。
在 4.5.0 版本之前,此类型仅包装模型的唯一字段。
selectXOR<UserSelect, null>指定要在返回对象上包含的属性
includeXOR<UserInclude, null>指定要在返回对象上急切加载的关系
omitXOR<UserOmit, null>指定要在返回对象上排除的属性。自 5.13.0 起处于预览状态。
relationLoadStrategy'join''query'默认值:join。指定关系查询的加载策略。仅与 include(或关系字段上的 select)结合使用。自 5.9.0 起处于预览状态。

返回类型

返回类型示例描述
JavaScript 对象(类型化)User
JavaScript 对象(普通){ name: "Alice Wonderland" }使用 selectinclude 确定要返回的字段。
PrismaClientKnownRequestError (代码 P2025)如果要更新的记录不存在,则抛出。请参阅错误参考

备注

  • 若要在更新时执行算术运算(加、减、乘、除),请使用原子更新以防止竞态条件。
  • 您还可以执行嵌套update - 例如,同时更新用户和该用户的帖子。

示例

id1User 记录的 email 更新为 alice@prisma.io
const user = await prisma.user.update({
where: { id: 1 },
data: { email: 'alice@prisma.io' },
});

upsert()

信息

本节介绍 upsert() 操作的用法。要了解如何在 update() 中使用嵌套 upsert 查询,请参阅链接文档。

upsert 执行以下操作

  • 如果现有数据库记录满足 where 条件,则更新该记录
  • 如果没有数据库记录满足 where 条件,则创建新的数据库记录

选项

名称类型必需描述
createXOR<UserCreateInput,
UserUncheckedCreateInput>
将模型的所有字段包装在一个类型中,以便在创建新记录时提供。它还包括关系字段,允许您执行(事务性)嵌套插入。在数据模型中标记为可选或具有默认值的字段是可选的。
updateXOR<UserUpdateInput,
UserUncheckedUpdateInput>
将模型的所有字段包装在一个类型中,以便在更新现有记录时提供。在数据模型中标记为可选或具有默认值的字段是可选的。
whereUserWhereUniqueInput包装模型的所有字段,以便可以选择记录(了解更多)。
在 4.5.0 版本之前,此类型仅包装模型的唯一字段。
selectXOR<UserSelect, null>指定要在返回对象上包含的属性
includeXOR<UserInclude, null>指定要在返回对象上急切加载的关系
omitXOR<UserOmit, null>指定要在返回对象上排除的属性。自 5.13.0 起处于预览状态
relationLoadStrategy'join''query'默认值:join。指定关系查询的加载策略。仅与 include(或关系字段上的 select)结合使用。自 5.9.0 起处于预览状态。

返回类型

返回类型示例描述
JavaScript 对象(类型化)User
JavaScript 对象(普通){ name: "Alice Wonderland" }使用 selectinclude 确定要返回的字段。

备注

  • 若要在更新时执行算术运算(加、减、乘、除),请使用原子更新以防止竞态条件。
  • 如果两个或多个 upsert 操作同时发生且记录尚不存在,则可能会发生竞态条件。结果,一个或多个 upsert 操作可能会抛出唯一键约束错误。您的应用程序代码可以捕获此错误并重试该操作。了解更多
  • 从版本 4.6.0 开始,Prisma ORM 会在可能的情况下将 upsert 查询交给数据库处理。了解更多

示例

更新(如果存在)或创建 emailalice@prisma.io 的新 User 记录
const user = await prisma.user.upsert({
where: { id: 1 },
update: { email: 'alice@prisma.io' },
create: { email: 'alice@prisma.io' },
});

upsert 上的唯一键约束错误

问题

如果多个 upsert 操作同时发生且记录尚不存在,则一个或多个操作可能会返回唯一键约束错误

原因

当 Prisma Client 执行 upsert 时,它首先检查该记录是否已存在于数据库中。为了执行此检查,Prisma Client 使用 upsert 操作中的 where 子句执行读取操作。这有两种可能的结果,如下所示

  • 如果记录不存在,则 Prisma Client 创建该记录。
  • 如果记录存在,则 Prisma Client 更新它。

当您的应用程序尝试执行两个或多个并发 upsert 操作时,可能会发生竞态条件,即两个或多个操作找不到记录,因此尝试创建该记录。在这种情况下,其中一个操作成功创建了新记录,但其他操作失败并返回唯一键约束错误。

解决方案

在您的应用程序代码中处理 P2002 错误。当它发生时,重试 upsert 操作以更新行。

数据库 upsert

在可能的情况下,Prisma Client 会将 upsert 查询交给数据库处理。这称为数据库 upsert

数据库 upsert 具有以下优点

当满足特定条件时,Prisma Client 会自动使用数据库 upsert。当不满足这些条件时,Prisma Client 会处理 upsert

要使用数据库 upsert,Prisma Client 会将 SQL 构造 INSERT ... ON CONFLICT SET .. WHERE 发送到数据库。

数据库 upsert 前提条件

如果您的堆栈满足以下条件,Prisma Client 可以使用数据库 upsert

  • 您使用 Prisma ORM 4.6.0 或更高版本
  • 您的应用程序使用 CockroachDB、PostgreSQL 或 SQLite 数据源
数据库 upsert 查询条件

upsert 查询满足以下条件时,Prisma Client 会使用数据库 upsert

  • upsertcreateupdate 选项中没有嵌套查询
  • 查询包含使用嵌套读取的选择
  • 查询仅修改一个模型
  • upsertwhere 选项中只有一个唯一字段
  • where 选项中的唯一字段和 create 选项中的唯一字段具有相同的值

如果您的查询不满足这些条件,则 Prisma Client 会自行处理 upsert。

数据库 upsert 示例

以下示例使用此 schema

model User {
id Int @id
profileViews Int
userName String @unique
email String

@@unique([id, profileViews])
}

以下 upsert 查询满足所有条件,因此 Prisma Client 使用数据库 upsert。

prisma.user.upsert({
where: {
userName: 'Alice',
},
create: {
id: 1,
profileViews: 1,
userName: 'Alice',
email: 'alice@prisma.io',
},
update: {
email: 'updated@example.com',
},
});

在这种情况下,Prisma 使用以下 SQL 查询

INSERT INTO "public"."User" ("id","profileViews","userName","email") VALUES ($1,$2,$3,$4)
ON CONFLICT ("userName") DO UPDATE
SET "email" = $5 WHERE ("public"."User"."userName" = $6 AND 1=1) RETURNING "public"."User"."id", "public"."User"."profileViews", "public"."User"."userName", "public"."User"."email"

以下查询的 where 子句中有多个唯一值,因此 Prisma Client 使用数据库 upsert

prisma.User.upsert({
where: {
userName: 'Alice',
profileViews: 1,
id: 1,
},
create: {
id: 1,
profileViews: 1,
userName: 'Alice',
email: 'alice@prisma.io',
},
update: {
email: 'updated@example.com',
},
});

在以下查询中,wherecreate 选项中的 userName 值不同,因此 Prisma Client 使用数据库 upsert。

prisma.User.upsert({
where: {
userName: 'Alice',
},
create: {
id: 1,
profileViews: 1,
userName: 'AliceS',
email: 'alice@prisma.io',
},
update: {
email: 'updated@example.com',
},
});

在以下查询中,poststitle 字段的选择是嵌套读取,因此 Prisma Client 使用数据库 upsert。

prisma.user.upsert({
select: {
email: true,
id: true,
posts: {
select: {
title: true,
},
},
},
where: {
userName: 'Alice',
},

create: {
id: 1,
profileViews: 1,
userName: 'Alice',
email: 'alice@prisma.io',
},
update: {
email: 'updated@example.com',
},
});

delete()

delete 删除现有数据库记录。您可以删除记录

  • ID
  • 唯一 属性

要删除符合特定条件的记录,请使用带筛选条件的deleteMany

选项

名称类型必需描述
whereUserWhereUniqueInput包装模型的所有字段,以便可以选择记录(了解更多)。
在 4.5.0 版本之前,此类型仅包装模型的唯一字段。
selectXOR<UserSelect, null>指定要在返回对象上包含的属性
includeXOR<UserInclude, null>指定要在返回对象上急切加载的关系
omitXOR<UserOmit, null>指定要在返回对象上排除的属性。自 5.13.0 起处于预览状态
relationLoadStrategy'join''query'默认值:join。指定关系查询的加载策略。仅与 include(或关系字段上的 select)结合使用。自 5.9.0 起处于预览状态。

返回类型

返回类型示例描述
JavaScript 对象(类型化)User已删除的 User 记录。
JavaScript 对象(普通){ name: "Alice Wonderland" }已删除的 User 记录中的数据。使用 selectinclude 确定要返回的字段。
PrismaClientKnownRequestError (代码 P2025)如果要删除的记录不存在,则抛出。请参阅错误参考

备注

  • 要根据某些条件删除多条记录(例如,所有具有 prisma.io 电子邮件地址的 User 记录),请使用 deleteMany

示例

删除 id1User 记录
const user = await prisma.user.delete({
where: { id: 1 },
});
删除 email 等于 elsa@prisma.ioUser 记录

以下查询删除特定用户记录并使用 select 返回已删除用户的 nameemail

const deleteUser = await prisma.user.delete({
where: {
email: 'elsa@prisma.io',
},
select: {
email: true,
name: true,
},
});
显示CLI结果
{ "email": "elsa@prisma.io", "name": "Elsa" }

createMany()

createMany 在事务中创建多条记录。

选项

名称类型必需描述
dataEnumerable<UserCreateManyInput>将所有模型字段包装在一个类型中,以便在创建新记录时提供。在数据模型中标记为可选或具有默认值的字段是可选的。
skipDuplicates?boolean不插入具有已存在的唯一字段或 ID 字段的记录。仅由支持 ON CONFLICT DO NOTHING 的数据库支持。这不包括 MongoDB 和 SQLServer

返回类型

返回类型示例描述
BatchPayload{ count: 3 }创建的记录数。

备注

  • 截至 Prisma ORM 5.12.0 版本,SQLite 现已支持 createMany()
  • MongoDB、SQLServer 或 SQLite 不支持 skipDuplicates 选项。
  • 不能通过在顶级 createMany() 查询中嵌套 createcreateManyconnectconnectOrCreate 查询来创建或连接关系。请参阅此处的解决方法。
  • 您可以在 update()create() 查询中嵌套 createMany 查询 - 例如,同时添加一个 User 和两个 Post 记录,其中包含嵌套的 createMany

示例

创建几个新用户
const users = await prisma.user.createMany({
data: [
{ name: 'Sonali', email: 'sonali@prisma.io' },
{ name: 'Alex', email: 'alex@prisma.io' },
],
});

createManyAndReturn()

createManyAndReturn 创建多条记录并返回结果对象。

信息

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

选项

名称类型必需描述
dataEnumerable<UserCreateManyInput>将所有模型字段包装在一个类型中,以便在创建新记录时提供。在数据模型中标记为可选或具有默认值的字段是可选的。
selectXOR<UserSelect, null>指定要在返回对象上包含的属性
omitXOR<UserOmit, null>指定要在返回对象上排除的属性。自 5.13.0 起处于预览状态。与 select 互斥。
includeXOR<UserInclude, null>指定要在返回对象上急切加载的关系
skipDuplicates?boolean不插入具有已存在的唯一字段或 ID 字段的记录。仅由支持 ON CONFLICT DO NOTHING 的数据库支持。这不包括 MongoDB 和 SQLServer

备注

  • SQLite 不支持 skipDuplicates 选项。
  • 请注意,createManyAndReturn 返回的元素的顺序不保证。
  • 不能通过在顶级 createManyAndReturn() 查询中嵌套 createcreateManyconnectconnectOrCreate 查询来创建或连接关系。请参阅此处的解决方法。
  • 当通过 include 包含关系时,每个关系都会生成一个单独的查询。
  • 不支持 relationLoadStrategy: join

返回类型

返回类型示例描述
JavaScript 数组对象(类型化)User[]
JavaScript 数组对象(普通)[{ name: "Sonali" }]使用 selectomitinclude 确定要返回的字段。

示例

创建并返回几个新用户
const users = await prisma.user.createManyAndReturn({
data: [
{ name: 'Sonali', email: 'sonali@prisma.io' },
{ name: 'Alex', email: 'alex@prisma.io' },
],
})
显示CLI结果
[
{ "id": 0, "name": "Sonali", "email": "sonali@prisma.io", "profileViews": 0 },
{ "id": 1, "name": "Alex", "email": "alex@prisma.io", "profileViews": 0 }
]

updateMany()

updateMany 批量更新一组现有数据库记录并返回更新的记录数。

选项

名称类型必需描述
dataXOR<UserUpdateManyMutationInput,
UserUncheckedUpdateManyInput>
将模型的所有字段包装在一个类型中,以便在更新现有记录时提供。在数据模型中标记为可选或具有默认值的字段在 data 上是可选的。
whereUserWhereInput将模型的所有字段包装在一个类型中,以便可以按任何属性筛选列表。如果您不筛选列表,所有记录都将更新。
limitnumber限制要更新的记录数。

返回类型

返回类型示例描述
BatchPayload{ count: 4 }已更新记录的计数。
export type BatchPayload = {
count: number;
};

示例

将所有 nameAliceUser 记录更新为 ALICE
const updatedUserCount = await prisma.user.updateMany({
where: { name: 'Alice' },
data: { name: 'ALICE' },
});
更新所有 User 记录,其中 email 包含 prisma.io 且至少一个相关 Post 具有超过 10 个赞
const updatedUserCount = await prisma.user.updateMany({
where: {
email: {
contains: 'prisma.io',
},
posts: {
some: {
likes: {
gt: 10,
},
},
},
},
data: {
role: 'USER',
},
});
更新 email 包含 prisma.ioUser 记录,但限制更新 5 条记录。
const updatedUserCount = await prisma.user.updateMany({
where: {
email: {
contains: 'prisma.io',
},
},
data: {
role: 'USER',
},
limit: 5,
});

updateManyAndReturn()

信息

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

updateManyAndReturn 更新多条记录并返回结果对象。

选项

名称类型必需描述
dataXOR<UserUpdateManyMutationInput,
UserUncheckedUpdateManyInput>
将模型的所有字段包装在一个类型中,以便在更新现有记录时提供。在数据模型中标记为可选或具有默认值的字段在 data 上是可选的。
whereUserWhereInput将模型的所有字段包装在一个类型中,以便可以按任何属性筛选列表。如果您不筛选列表,所有记录都将更新。

返回类型

返回类型示例描述
JavaScript 数组对象(类型化)User[]
JavaScript 数组对象(普通)[{ name: "Sonali" }]使用 selectomitinclude 确定要返回的字段。

示例

更新并返回多个用户
const users = await prisma.user.updateManyAndReturn({
where: {
email: {
contains: 'prisma.io',
}
},
data: {
role: 'ADMIN'
},
})
显示CLI结果
[
{ "id": 0, "name": "Sonali", "email": "sonali@prisma.io", "role": "ADMIN", "profileViews": 0 },
{ "id": 1, "name": "Alex", "email": "alex@prisma.io", "role": "ADMIN", "profileViews": 0 }
]

deleteMany()

deleteMany 在事务中删除多条记录。

选项

名称类型必需描述
whereUserWhereInput将模型的所有字段包装在一个类型中,以便可以按任何字段筛选列表。
limitInt限制已删除记录的数量。

返回类型

返回类型示例描述
BatchPayload{ count: 4 }已删除记录的计数。
export type BatchPayload = {
count: number;
};

示例

删除所有 User 记录
const deletedUserCount = await prisma.user.deleteMany({});
删除所有 nameAliceUser 记录
const deletedUserCount = await prisma.user.deleteMany({
where: { name: 'Alice' },
});
删除 email 包含 prisma.io 的所有 User 记录,但限制删除 5 条记录。
const deletedUserCount = await prisma.user.deleteMany({
where: {
email: {
contains: 'prisma.io',
},
},
limit: 5,
});

请参阅筛选条件和运算符,了解如何筛选要删除的记录的示例。

count()

选项

名称类型必需描述
whereUserWhereInput所有模型字段包装在一个类型中,以便可以按任何属性筛选列表。
orderByXOR<Enumerable<PostOrder
ByInput>, PostOrderByInput>
允许您按任何属性排序返回的列表。
cursorUserWhereUniqueInput指定列表的位置(值通常指定 id 或另一个唯一值)。
takenumber指定列表中应返回的对象数量(从列表的开头(正值)或结尾(负值)从提及的 cursor 位置看)
skipnumber指定列表中应跳过的返回对象数量。

返回类型

返回类型示例描述
number29记录数。
UserCountAggregateOutputType{ _all: 27, name: 10 }如果使用 select 则返回。

示例

计算所有 User 记录
const result = await prisma.user.count();
计算所有至少有一篇已发布 PostUser 记录
const result = await prisma.user.count({
where: {
post: {
some: {
published: true,
},
},
},
});
使用 select 执行三个独立的计数

以下查询返回

  • 所有记录的计数(_all
  • 所有具有非 null name 字段的记录的计数
  • 所有具有非 null city 字段的记录的计数
const c = await prisma.user.count({
select: {
_all: true,
city: true,
name: true,
},
});

aggregate()

另请参阅:聚合、分组和汇总

选项

名称类型必需描述
whereUserWhereInput所有模型字段包装在一个类型中,以便可以按任何属性筛选列表。
orderByXOR<Enumerable<UserOrderByInput>,
UserOrderByInput>
允许您按任何属性排序返回的列表。
cursorUserWhereUniqueInput指定列表的位置(值通常指定 id 或另一个唯一值)。
takenumber指定列表中应返回的对象数量(从列表的开头(正值)或结尾(负值)从提及的 cursor 位置看)
skipnumber指定列表中应跳过的返回对象数量。
_counttrue返回匹配记录或非 null 字段的计数。
_avgUserAvgAggregateInputType返回指定字段所有值的平均值。
_sumUserSumAggregateInputType返回指定字段所有值的总和。
_minUserMinAggregateInputType返回指定字段的最小可用值。
_maxUserMaxAggregateInputType返回指定字段的最大可用值。

示例

返回所有 User 记录的 profileViews_min_max_count
const minMaxAge = await prisma.user.aggregate({
_count: {
_all: true,
},
_max: {
profileViews: true,
},
_min: {
profileViews: true,
},
});
显示CLI结果
返回所有 User 记录的 profileViews_sum
const setValue = await prisma.user.aggregate({
_sum: {
profileViews: true,
},
});
显示CLI结果

groupBy()

另请参阅:聚合、分组和汇总

选项

名称类型必需描述
whereUserWhereInput所有模型字段包装在一个类型中,以便可以按任何属性筛选列表。
orderByXOR<Enumerable<UserOrderByInput>,
UserOrderByInput>
允许您按 by 中也存在的任何属性排序返回的列表。
byArray<UserScalarFieldEnum> | string指定用于对记录进行分组的字段或字段组合。
havingUserScalarWhereWithAggregatesInput允许您按聚合值筛选组 - 例如,仅返回平均年龄小于 50 的组。
takenumber指定列表中应返回的对象数量(从列表的开头(正值)或结尾(负值)从提及的 cursor 位置看)
skipnumber指定列表中应跳过的返回对象数量。
_counttrue | UserCountAggregateInputType返回匹配记录或非 null 字段的计数。
_avgUserAvgAggregateInputType返回指定字段所有值的平均值。
_sumUserSumAggregateInputType返回指定字段所有值的总和。
_minUserMinAggregateInputType返回指定字段的最小可用值。
_maxUserMaxAggregateInputType返回指定字段的最大可用值。

示例

country/city 分组,其中平均 profileViews 大于 200,并返回每个组的 profileViews_sum

该查询还返回每个组中 _all 记录的计数,以及每个组中具有非 null city 字段值的所有记录。

const groupUsers = await prisma.user.groupBy({
by: ['country', 'city'],
_count: {
_all: true,
city: true,
},
_sum: {
profileViews: true,
},
orderBy: {
country: 'desc',
},
having: {
profileViews: {
_avg: {
gt: 200,
},
},
},
});
显示CLI结果
[
{
country: 'Denmark',
city: 'Copenhagen',
_sum: { profileViews: 490 },
_count: {
_all: 70,
city: 8,
},
},
{
country: 'Sweden',
city: 'Stockholm',
_sum: { profileViews: 500 },
_count: {
_all: 50,
city: 3,
},
},
];

findRaw()

请参阅:使用原始 SQL (findRaw())

aggregateRaw()

请参阅:使用原始 SQL (aggregateRaw())

模型查询选项

select

select 定义 Prisma Client 返回的对象中包含哪些字段。请参阅:选择字段和包含关系

备注

示例

选择单个 User 记录的 nameprofileViews 字段
const result = await prisma.user.findUnique({
where: { id: 1 },
select: {
name: true,
profileViews: true,
},
});
显示CLI结果
选择多个 User 记录的 emailrole 字段
const result = await prisma.user.findMany({
select: {
email: true,
role: true,
},
});
显示CLI结果
选择关系的 _count
const usersWithCount = await prisma.user.findMany({
select: {
_count: {
select: { posts: true },
},
},
});
显示CLI结果
选择相关 Post 记录的 'id' 和 'title' 字段
const result = await prisma.user.findMany({
select: {
id: true,
name: true,
posts: {
select: {
id: true,
title: true,
},
},
},
});
显示CLI结果
includeselect
const result = await prisma.user.findMany({
select: {
id: true,
name: true,
posts: {
include: {
author: true,
},
},
},
});
显示CLI结果

select 的生成类型

以下示例演示如何将 validatorselect 配合使用

const selectNameEmailNotPosts = Prisma.validator<Prisma.UserSelect>()({
name: true,
email: true,
posts: false,
});

include

include 定义 Prisma Client 返回的结果中包含哪些关系。请参阅:选择字段和包含关系

备注

示例

加载 User 记录时包含 postsprofile 关系
const users = await prisma.user.findMany({
include: {
posts: true, // Returns all fields for all posts
profile: true, // Returns all Profile fields
},
});
创建具有两个 Post 记录的新 User 记录时,在返回对象上包含 posts 关系
const user = await prisma.user.create({
data: {
email: 'alice@prisma.io',
posts: {
create: [{ title: 'This is my first post' }, { title: 'Here comes a second post' }],
},
},
include: { posts: true }, // Returns all fields for all posts
});

include 的生成类型

以下示例演示如何将 validatorinclude 配合使用

const includePosts = Prisma.validator<Prisma.UserInclude>()({
posts: true,
});
包含关系的 _count
const usersWithCount = await prisma.user.findMany({
include: {
_count: {
select: { posts: true },
},
},
});
显示CLI结果

omit

omit 定义 Prisma Client 返回的对象中排除哪些字段。

备注

  • 您不能组合 omitselect,因为它们的目的相反
  • omit 随 Prisma ORM 6.2.0 发布到普遍可用。它在 Prisma ORM 5.13.06.1.0 版本中通过 omitApi 预览功能可用。

示例

从所有 User 记录中省略 password 字段
const result = await prisma.user.findMany({
omit: {
password: true,
},
});
显示CLI结果
从所有 Userposts 关系中省略 title 字段
const results = await prisma.user.findMany({
omit: {
password: true,
},
include: {
posts: {
omit: {
title: true,
},
},
},
});
显示CLI结果

omit 的生成类型

以下示例演示如何将 validatoromit 配合使用

const omitPassword = Prisma.validator<Prisma.UserOmit>()({
password: true,
});

relationLoadStrategy(预览)

relationLoadStrategy 指定关系应如何从数据库加载。它有两个可能的值

  • join(默认):使用数据库级别的 LATERAL JOIN (PostgreSQL) 或相关子查询 (MySQL),并通过单个查询从数据库获取所有数据。
  • query:向数据库发送多个查询(每个表一个)并在应用程序级别进行连接。

注意:一旦 relationLoadStrategy预览进入普遍可用join 将普遍成为所有关系查询的默认值。

您可以在此处了解有关连接策略的更多信息。

由于 relationLoadStrategy 选项目前处于预览状态,您需要通过 Prisma schema 文件中的 relationJoins 预览功能标志启用它

generator client {
provider = "prisma-client"
output = "./generated"
previewFeatures = ["relationJoins"]
}

添加此标志后,您需要再次运行 prisma generate 以重新生成 Prisma Client。relationJoins 功能目前在 PostgreSQL、CockroachDB 和 MySQL 上可用。

备注

  • 在大多数情况下,默认的 join 策略会更有效。如果您想节省数据库服务器上的资源,或者如果您通过分析发现应用程序级别的连接性能更好,请使用 query
  • 您只能在查询的顶层指定 relationLoadStrategy。顶层选择将影响所有嵌套子查询。

示例

在使用 include 时通过数据库级别 JOIN 加载 posts 关系
const users = await prisma.user.findMany({
relationLoadStrategy: 'join',
include: {
posts: true,
},
});
在使用 select 时通过数据库级别 JOIN 加载 posts 关系
const users = await prisma.user.findMany({
relationLoadStrategy: 'join',
select: {
posts: true,
},
});

where

where 定义一个或多个筛选器,可用于筛选记录属性(如用户的电子邮件地址)或相关记录属性(如用户最近 10 篇帖子标题)。

示例

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

where 的生成类型

以下示例演示如何将 validatorwhere 配合使用

  • UserWhereInput

    // UserWhereInput
    const whereNameIs = Prisma.validator<Prisma.UserWhereInput>()({
    name: 'Rich',
    });

    // It can be combined with conditional operators too
    const whereNameIs = Prisma.validator<Prisma.UserWhereInput>()({
    name: 'Rich',
    AND: [
    {
    email: {
    contains: 'rich@boop.com',
    },
    },
    ],
    });
  • UserWhereUniqueInput 此类型通过公开模型上的任何唯一字段来工作。被指定 @id 的字段被认为是唯一的,被指定 @unique 的字段也是如此。

    从版本 4.5.0 开始,此类型公开模型上的所有字段。这意味着当您根据唯一字段筛选单个记录时,您可以同时检查其他非唯一和唯一字段。了解更多

    // UserWhereUniqueInput
    const whereEmailIsUnique = Prisma.validator<Prisma.UserWhereUniqueInput>()({
    email: 'rich@boop.com',
    })
  • PostScalarWhereInput

    const whereScalarTitleIs = Prisma.validator<Prisma.PostScalarWhereInput>()({
    title: 'boop',
    });
  • PostUpdateWithWhereUniqueWithoutAuthorInput - 此类型接受唯一的 where 字段(@id 或另一个指定的 @unique),并更新 Post 模型上的任何字段,除了 AuthorAuthorPost 模型上的标量字段。

    const updatePostByIdWithoutAuthor =
    Prisma.validator<Prisma.PostUpdateWithWhereUniqueWithoutAuthorInput>()({
    where: {
    id: 1,
    },
    data: {
    content: 'This is some updated content',
    published: true,
    title: 'This is a new title',
    },
    });
  • PostUpsertWithWhereUniqueWithoutAuthorInput - 此类型将更新 Post 记录的标题字段,其中 id 匹配,如果不存在则会创建它。

    const updatePostTitleOrCreateIfNotExist =
    Prisma.validator<Prisma.PostUpsertWithWhereUniqueWithoutAuthorInput>()({
    where: {
    id: 1,
    },
    update: {
    title: 'This is a new title',
    },
    create: {
    id: 1,
    title: 'If the title doesnt exist, then create one with this text',
    },
    });
  • PostUpdateManyWithWhereWithoutAuthorInput - 此类型将更新所有 Post 记录,其中 published 设置为 false。

    const publishAllPosts = Prisma.validator<Prisma.PostUpdateManyWithWhereWithoutAuthorInput>()({
    where: {
    published: {
    equals: false,
    },
    },
    data: {
    published: true,
    },
    });

orderBy

对记录列表进行排序。另请参阅:排序

备注

sort 参数的输入

名称描述
asc升序排序 (A → Z)
desc降序排序 (Z → A)

nulls 参数的输入

注意

  • 此参数是可选的。
  • 它仅用于可选标量字段。如果您尝试按必需或关系字段上的 null 值排序,Prisma Client 会抛出 P2009 错误
  • 它在 4.1.0 及更高版本中可用,作为预览功能。请参阅首先或最后排序 null 记录,了解如何启用该功能的详细信息。
名称描述
firstnull 值首先排序。
lastnull 值最后排序。

示例

email 字段排序 User

以下示例返回所有按 email 升序排序的 User 记录

const users = await prisma.user.findMany({
orderBy: {
email: 'asc',
},
});

以下示例返回所有按 email 降序排序的 User 记录

const users = await prisma.user.findMany({
orderBy: {
email: 'desc',
},
});

按相关 User 记录的 name 排序 Post

以下查询按用户姓名排序帖子

const posts = await prisma.post.findMany({
orderBy: {
author: {
name: 'asc',
},
},
});

按相关 User 记录的 name 排序 Postnull 记录优先

以下查询按用户姓名排序帖子,null 记录优先

const posts = await prisma.post.findMany({
orderBy: {
author: {
name: { sort: 'asc', nulls: 'first' },
},
},
});

按标题相关性排序 Post

信息

对于 PostgreSQL,此功能仍在预览中。请启用 fullTextSearchPostgres 功能标志才能使用它。

以下查询按搜索词 'database' 与标题的相关性排序帖子

const posts = await prisma.post.findMany({
orderBy: {
_relevance: {
fields: ['title'],
search: 'database',
sort: 'asc'
},
})

posts 计数排序 User

以下查询按帖子计数排序用户

const getActiveusers = await prisma.user.findMany({
orderBy: {
posts: {
count: 'desc',
},
},
});
按多个字段排序 User - email role

以下示例按两个字段排序用户 - 首先是 email,然后是 role

const users = await prisma.user.findMany({
select: {
email: true,
role: true,
},
orderBy: [
{
email: 'desc',
},
{
role: 'desc',
},
],
});
显示CLI结果

排序参数的顺序很重要 - 以下查询按 role 排序,然后是 email。请注意结果的差异

const users = await prisma.user.findMany({
select: {
email: true,
role: true,
},
orderBy: [
{
role: 'desc',
},
{
email: 'desc',
},
],
});
显示CLI结果
email 排序 User,选择 nameemail

以下示例返回所有 User 记录的 nameemail 字段,按 email 排序

const users3 = await prisma.user.findMany({
orderBy: {
email: 'asc',
},
select: {
name: true,
email: true,
},
});
显示CLI结果
email 排序 User 记录,并按 title 排序嵌套的 Post 记录

以下示例

  • 返回所有按 email 排序的 User 记录
  • 对于每个 User 记录,返回所有按 title 排序的嵌套 Post 记录的 title 字段
const usersWithPosts = await prisma.user.findMany({
orderBy: {
email: 'asc',
},
include: {
posts: {
select: {
title: true,
},
orderBy: {
title: 'asc',
},
},
},
});
显示CLI结果
排序一个用户的嵌套 Post 记录列表

以下示例通过 ID 检索单个 User 记录,以及一个按 title 排序的嵌套 Post 记录列表

const userWithPosts = await prisma.user.findUnique({
where: {
id: 1,
},
include: {
posts: {
orderBy: {
title: 'desc',
},
select: {
title: true,
published: true,
},
},
},
});
显示CLI结果
enum 排序

以下按 role(一个 enum)排序所有 User 记录

const sort = await prisma.user.findMany({
orderBy: {
role: 'desc',
},
select: {
email: true,
role: true,
},
});
显示CLI结果

orderBy 的生成类型

以下示例演示如何将 validatororderBy 配合使用

  • UserOrderByInput
    const orderEmailsByDescending = Prisma.validator<Prisma.UserOrderByInput>()({
    email: 'desc',
    });

distinct

findManyfindFirst 中删除记录列表中的重复项。另请参阅:聚合、分组和汇总

示例

在单个字段上选择 distinct

以下示例返回所有不同的 city 字段,并仅选择 citycountry 字段

const distinctCities = await prisma.user.findMany({
select: {
city: true,
country: true,
},
distinct: ['city'],
});
显示CLI结果
[
{ city: 'Paris', country: 'France' },
{ city: 'Lyon', country: 'France' },
];
在多个字段上选择 distinct

以下示例返回所有不同的 city country 字段组合,并仅选择 citycountry 字段

const distinctCitiesAndCountries = await prisma.user.findMany({
select: {
city: true,
country: true,
},
distinct: ['city', 'country'],
});
显示CLI结果
[
{ city: 'Paris', country: 'France' },
{ city: 'Paris', country: 'Denmark' },
{ city: 'Lyon', country: 'France' },
];

请注意,现在除了“法国巴黎”之外,还有一个“丹麦巴黎”

选择 distinct 与筛选器结合使用

以下示例返回所有不同的 city country 字段组合,其中用户电子邮件包含 "prisma.io",并仅选择 citycountry 字段

const distinctCitiesAndCountries = await prisma.user.findMany({
where: {
email: {
contains: 'prisma.io',
},
},
select: {
city: true,
country: true,
},
distinct: ['city', 'country'],
});
显示CLI结果

nativeDistinct

在您的 Prisma schema 中启用 nativeDistinct 会将 distinct 操作推送到数据库层(如果支持)。这可以显著提高性能。但是,请注意

  • 某些数据库可能不支持某些字段组合上的 DISTINCT。
  • 不同提供商的行为可能不同。

要启用 nativeDistinct

generator client {
provider = "prisma-client"
output = "./generated"
previewFeatures = ["nativeDistinct"]
}

See [Preview Features](/orm/reference/preview-features/client-preview-features#preview-features-promoted-to-general-availability) for more details.

## Nested queries

### `create`

A nested `create` query adds a new related record or set of records to a parent record. See: [Working with relations](/orm/prisma-client/queries/relation-queries)

#### Remarks

- `create` is available as a nested query when you `create()` (`prisma.user.create(...)`) a new parent record or `update()` (`prisma.user.update(...)`) an existing parent record.
- You can use a nested `create` _or_ a nested [`createMany`](#createmany-1) to create multiple related records. If you require the [`skipDuplicates` query option](#nested-createmany-options) you should use `createMany`.

#### Examples

##### Create a new `User` record with a new `Profile` record

```ts highlight=5;normal
const user = await prisma.user.create({
data: {
email: 'alice@prisma.io',
profile: {
create: { bio: 'Hello World' },
},
},
});
使用新的 User 记录创建新的 Profile 记录
const user = await prisma.profile.create({
data: {
bio: 'Hello World',
user: {
create: { email: 'alice@prisma.io' },
},
},
})
使用新的 Post 记录创建新的 User 记录
const user = await prisma.user.create({
data: {
email: 'alice@prisma.io',
posts: {
create: { title: 'Hello World' },
},
},
});
使用两个新的 Post 记录创建新的 User 记录

由于它是一对多关系,您还可以通过向 create 传递数组来一次创建多个 Post 记录

const user = await prisma.user.create({
data: {
email: 'alice@prisma.io',
posts: {
create: [
{
title: 'This is my first post',
},
{
title: 'Here comes a second post',
},
],
},
},
});

注意:您还可以使用嵌套的 createMany 来实现相同的结果。

通过创建新的 Profile 记录更新现有 User 记录
const user = await prisma.user.update({
where: { email: 'alice@prisma.io' },
data: {
profile: {
create: { bio: 'Hello World' },
},
},
});
通过创建新的 Post 记录更新现有 User 记录
const user = await prisma.user.update({
where: { email: 'alice@prisma.io' },
data: {
posts: {
create: { title: 'Hello World' },
},
},
})

createMany

嵌套的 createMany 查询向父记录添加一组新记录。请参阅:使用关系

备注

  • 当您 create() (prisma.user.create(...)) 新的父记录或 update() (prisma.user.update(...)) 现有父记录时,createMany 可作为嵌套查询使用。
    • 在一对多关系上下文中使用 — 例如,您可以 prisma.user.create(...) 创建一个用户,并使用嵌套的 createMany 创建多个帖子(帖子有一个用户)。
    • 在多对多关系上下文中可用 — 例如,您不能 prisma.post.create(...) 创建一个帖子,并使用嵌套的 createMany 创建多个类别(多个帖子有多个类别)。
  • 您不能嵌套额外的 createcreateMany
  • 允许直接设置外键 — 例如,设置帖子的 categoryId
  • 自 Prisma ORM 5.12.0 版本起,SQLite 支持嵌套的 createMany
  • 您可以使用嵌套的 create 嵌套的 createMany 创建多个相关记录 — 如果您不需要 skipDuplicates 查询选项,您可能应该使用 create

选项

名称类型必需描述
dataEnumerable<UserCreateManyInput>将所有模型字段包装在一个类型中,以便在创建新记录时提供。在数据模型中标记为可选或具有默认值的字段是可选的。
skipDuplicates?boolean不插入具有已存在的唯一字段或 ID 字段的记录。仅由支持 ON CONFLICT DO NOTHING 的数据库支持。这不包括 MongoDB 和 SQLServer

示例

更新一个 User 和多个新的相关 Post 记录
const user = await prisma.user.update({
where: {
id: 9,
},
data: {
name: 'Elliott',
posts: {
createMany: {
data: [{ title: 'My first post' }, { title: 'My second post' }],
},
},
},
});

set

set 覆盖关系的值 — 例如,用不同的列表替换 Post 记录列表。参见:处理关系

示例

更新现有 User 记录,断开任何之前的 Post 记录,并连接另外两条现有记录
const user = await prisma.user.update({
where: { email: 'alice@prisma.io' },
data: {
posts: {
set: [{ id: 32 }, { id: 42 }],
},
},
});

connect

嵌套的 connect 查询通过指定 ID 或唯一标识符将记录连接到现有相关记录。参见:处理关系

备注

  • 当您创建新的父记录或更新现有父记录时,connect 可作为嵌套查询使用。

  • 如果相关记录不存在,Prisma Client 将抛出异常。

    The required connected records were not found. Expected 1 records to be connected, found 0.
  • setconnect 一起使用时,它们的应用顺序会显著影响结果。如果 setconnect 之前使用,则连接的记录将只反映 connect 操作建立的最终状态,因为 set 会在 connect 建立新连接之前清除所有现有连接。相反,如果 connectset 之前应用,则 set 操作将通过清除所有连接的记录并用其自己的指定状态替换它们来覆盖 connect 操作。

示例

创建一个新的 Profile 记录并通过唯一字段将其连接到现有 User 记录
const user = await prisma.profile.create({
data: {
bio: 'Hello World',
user: {
connect: { email: 'alice@prisma.io' },
},
},
});
创建一个新的 Profile 记录并通过 ID 字段将其连接到现有 User 记录
const user = await prisma.profile.create({
data: {
bio: 'Hello World',
user: {
connect: { id: 42 }, // sets userId of Profile record
},
},
});

2.11.0 及更高版本中,您可以直接设置外键。

const user = await prisma.profile.create({
data: {
bio: 'Hello World',
userId: 42,
},
});

但是,您不能在同一查询中同时使用直接方法和 connect 方法。详情请参阅 此问题评论

创建一个新的 Post 记录并将其连接到现有 User 记录
const user = await prisma.post.create({
data: {
title: 'Hello World',
author: {
connect: { email: 'alice@prisma.io' },
},
},
});
通过连接到现有 Profile 记录来更新现有 User 记录
const user = await prisma.user.update({
where: { email: 'alice@prisma.io' },
data: {
profile: {
connect: { id: 24 },
},
},
});
通过连接到两条现有 Post 记录来更新现有 User 记录
const user = await prisma.user.update({
where: { email: 'alice@prisma.io' },
data: {
posts: {
connect: [{ id: 24 }, { id: 42 }],
},
},
});

connectOrCreate

connectOrCreate 要么通过 ID 或唯一标识符将记录连接到现有相关记录,要么在记录不存在时创建新的相关记录。参见:处理关系

备注

  • 作为并发事务运行的多个 connectOrCreate 查询可能导致竞态条件。考虑以下示例,其中两个查询同时尝试 connectOrCreate 一个名为 computing 的博客文章标签(标签名称必须唯一)

    const createPost = await prisma.post.create({
    data: {
    title: 'How to create a compiler',
    content: '...',
    author: {
    connect: {
    id: 9,
    },
    },
    tags: {
    connectOrCreate: {
    create: {
    name: 'computing',
    },
    where: {
    name: 'computing',
    },
    },
    },
    },
    })

    如果查询 A 和查询 B 以以下方式重叠,则查询 A 将导致异常。

    查询 A(失败 ❌)查询 B(成功 ✅)
    查询到达服务器,开始事务 A查询到达服务器,开始事务 B
    查找 tagName 等于 computing 的记录,未找到记录
    查找 tagName 等于 computing 的记录,未找到记录
    创建 tagName 等于 computing 的记录并连接
    创建 tagName 等于 computing 的记录
    唯一性冲突,记录已被事务 B 创建

    为解决此情况,我们建议捕获唯一性冲突异常 (PrismaClientKnownRequestError,错误 P2002) 并重试失败的查询。

示例

创建新的 Profile 记录,然后将其连接到现有 User 记录 创建新的 User

以下示例

  1. 创建一个 Profile
  2. 尝试将个人资料连接到电子邮件地址为 alice@prisma.ioUser
  3. 如果不存在匹配用户,则创建新用户
const user = await prisma.profile.create({
data: {
bio: 'The coolest Alice on the planet',
user: {
connectOrCreate: {
where: { email: 'alice@prisma.io' },
create: { email: 'alice@prisma.io'}
},
},
})
创建新的 Post 记录并将其连接到现有 User 记录, 创建新的 User
const user = await prisma.post.create({
data: {
title: 'Hello World',
author: {
connectOrCreate: {
where: { email: 'alice@prisma.io' },
create: { email: 'alice@prisma.io' },
},
},
},
});
通过连接到现有 Profile 记录, 创建新的 Profile 记录来更新现有 User 记录

以下示例

  1. 尝试将用户连接到 id20Profile
  2. 如果不存在匹配的个人资料,则创建新的个人资料
const updateUser = await prisma.user.update({
where: { email: 'alice@prisma.io' },
data: {
profile: {
connectOrCreate: {
where: { id: 20 },
create: {
bio: 'The coolest Alice in town',
},
},
},
},
});
通过连接到两条现有 Post 记录,或创建两条新的 Post 记录来更新现有 User 记录
const user = await prisma.user.update({
where: { email: 'alice@prisma.io' },
data: {
posts: {
connectOrCreate: [
{
where: { id: 32 },
create: { title: 'This is my first post' },
},
{
where: { id: 19 },
create: { title: 'This is my second post' },
},
],
},
},
});

disconnect

嵌套的 disconnect 查询会中断父记录和相关记录之间的连接,但不会删除任何一条记录。参见:处理关系

备注

  • disconnect 仅当关系是可选的时才可用。

  • 如果您尝试断开的关系不存在

    • (在 2.21.0 及更高版本中),该操作不执行任何操作。

    • (在 2.21.0 之前) 如果提供的 ID 或唯一标识符未连接,Prisma Client 将抛出异常。

      The records for relation `PostToUser` between the `User` and `Post` models are not connected.

示例

通过断开连接的 Profile 记录来更新现有 User 记录
const user = await prisma.user.update({
where: { email: 'bob@prisma.io' },
data: {
profile: {
disconnect: true,
},
},
});
通过断开连接的两条 Post 记录来更新现有 User 记录
const user = await prisma.user.update({
where: { email: 'alice@prisma.io' },
data: {
posts: {
disconnect: [{ id: 44 }, { id: 46 }],
},
},
});

update

嵌套的 update 查询更新一条或多条相关记录,其中父记录的 ID 为 n。参见:处理关系

备注

  • 嵌套的 update 查询仅在顶级 update 查询(例如,prisma.user.update(...))的上下文中可用。

  • 如果父记录不存在,Prisma Client 将抛出异常。

    AssertionError("Expected a valid parent ID to be present for nested update to-one case.")
  • 如果您想要更新的相关记录不存在,Prisma Client 将抛出异常。

    AssertionError("Expected a valid parent ID to be present for nested update to-one case.")

示例

通过更新连接的 Profile 记录来更新现有 User 记录
const user = await prisma.user.update({
where: { email: 'alice@prisma.io' },
data: {
profile: {
update: { bio: 'Hello World' },
},
},
});
通过更新连接的两条 Post 记录来更新现有 User 记录
const user = await prisma.user.update({
where: { email: 'alice@prisma.io' },
data: {
posts: {
update: [
{
data: { published: true },
where: { id: 32 },
},
{
data: { published: true },
where: { id: 23 },
},
],
},
},
});

upsert

信息

本节涵盖 update() 中嵌套 upsert 的用法。要了解 upsert() 操作,请参考链接文档。

嵌套的 upsert 查询在相关记录存在时更新它,否则创建新的相关记录。

示例

通过更新连接的 Profile 记录或创建新的 Profile 记录来更新现有 User 记录 (upsert)
const user = await prisma.user.update({
where: { email: 'alice@prisma.io' },
data: {
profile: {
upsert: {
create: { bio: 'Hello World' },
update: { bio: 'Hello World' },
},
},
},
});
通过更新连接的两条 Post 记录或创建新的 Post 记录来更新现有 User 记录 (upsert)
const user = await prisma.user.update({
where: { email: 'alice@prisma.io' },
data: {
posts: {
upsert: [
{
create: { title: 'This is my first post' },
update: { title: 'This is my first post' },
where: { id: 32 },
},
{
create: { title: 'This is my second post' },
update: { title: 'This is my second post' },
where: { id: 23 },
},
],
},
},
});

delete

嵌套的 delete 查询删除相关记录。父记录不会被删除。

备注

  • delete 仅当关系是可选的时才可用。

示例

通过删除连接的 Profile 记录来更新现有 User 记录
const user = await prisma.user.update({
where: { email: 'alice@prisma.io' },
data: {
profile: {
delete: true,
},
},
});
通过删除连接的两条 Post 记录来更新现有 User 记录
const user = await prisma.user.update({
where: { email: 'alice@prisma.io' },
data: {
posts: {
delete: [{ id: 34 }, { id: 36 }],
},
},
});

updateMany

嵌套的 updateMany 更新相关记录列表并支持过滤 — 例如,您可以更新用户的未发布帖子。

示例

更新属于特定用户的所有未发布帖子
const result = await prisma.user.update({
where: {
id: 2,
},
data: {
posts: {
updateMany: {
where: {
published: false,
},
data: {
likes: 0,
},
},
},
},
});

deleteMany

嵌套的 deleteMany 删除相关记录并支持过滤。例如,您可以在更新该用户的其他属性时删除用户的帖子。

示例

作为更新的一部分删除属于特定用户的所有帖子
const result = await prisma.user.update({
where: {
id: 2,
},
data: {
name: 'Updated name',
posts: {
deleteMany: {},
},
},
});

过滤条件和运算符

equals

值等于 n

示例

返回所有 name 等于 "Eleanor" 的用户

const result = await prisma.user.findMany({
where: {
name: {
equals: 'Eleanor',
},
},
});

您也可以排除 equals

const result = await prisma.user.findMany({
where: {
name: 'Eleanor',
},
});

返回所有数量低于“警告数量”阈值的产品

此示例比较同一模型的字段,此功能自 4.3.0 版起可用。

const productsWithLowQuantity = await prisma.product.findMany({
where: {
quantity: {
lte: prisma.product.fields.warnQuantity
},
},
});

返回所有将蓝色和绿色设置为其喜爱颜色的用户

此示例查找将 favoriteColors 字段设置为 ['blue', 'green'] 的用户。

请注意,在使用 equals 时,元素的顺序很重要。也就是说 ['blue', 'green'] 等于 ['green', 'blue']

const favoriteColorFriends = await prisma.user.findMany({
where: {
favoriteColors: {
equals: ['blue', 'green'],
},
},
});

not

值不等于 n

示例

返回所有 name 等于 "Eleanor" 的用户
const result = await prisma.user.findMany({
where: {
name: {
not: 'Eleanor',
},
},
});
警告

not 将返回所有不匹配给定值的项目。但是,如果列可为空,则不会返回 NULL 值。如果您需要返回 null 值,请使用 OR 运算符包含 NULL 值。

返回所有 name 等于 "Eleanor" 的用户,包括 nameNULL 的用户
await prisma.user.findMany({
where: {
OR: [
{ name: { not: 'Eleanor' } },
{ name: null }
]
}
})

in

n 存在于列表中。

注意

不返回 null 值。例如,如果您结合使用 inNOT 返回名称不在列表中的用户,则不会返回名称为 null 值的用户。

示例

获取 id 可以在以下列表中找到的 User 记录:[22, 91, 14, 2, 5]
const getUser = await prisma.user.findMany({
where: {
id: { in: [22, 91, 14, 2, 5] },
},
});
获取 name 可以在以下列表中找到的 User 记录:['Saqui', 'Clementine', 'Bob']
const getUser = await prisma.user.findMany({
where: {
name: { in: ['Saqui', 'Clementine', 'Bob'] },
},
});
获取 name 不在列表中的 User 记录

以下示例结合了 inNOT。您也可以使用 notIn

const getUser = await prisma.user.findMany({
where: {
NOT: {
name: { in: ['Saqui', 'Clementine', 'Bob'] },
},
},
});
获取至少有一篇 Post 包含至少一个指定 CategoryUser 记录
const getUser = await prisma.user.findMany({
where: {
// Find users where..
posts: {
some: {
// ..at least one (some) posts..
categories: {
some: {
// .. have at least one category ..
name: {
in: ['Food', 'Introductions'], // .. with a name that matches one of the following.
},
},
},
},
},
},
});

notIn

n 不存在于列表中。

备注

  • 不返回 null 值。

示例

获取 id 在以下列表中的 User 记录:[22, 91, 14, 2, 5]
const getUser = await prisma.user.findMany({
where: {
id: { notIn: [22, 91, 14, 2, 5] },
},
});

lt

n 小于 x

示例

获取所有 likes 小于 9Post 记录
const getPosts = await prisma.post.findMany({
where: {
likes: {
lt: 9,
},
},
});

lte

n 小于等于 x

示例

获取所有 likes 小于或等于 9Post 记录
const getPosts = await prisma.post.findMany({
where: {
likes: {
lte: 9,
},
},
});

gt

n 大于 x

示例

获取所有 likes 大于 9Post 记录
const getPosts = await prisma.post.findMany({
where: {
likes: {
gt: 9,
},
},
});

gte

n 大于等于 x

示例

获取所有 likes 大于或等于 9Post 记录
const getPosts = await prisma.post.findMany({
where: {
likes: {
gte: 9,
},
},
});

示例

获取所有 date_created 晚于 2020 年 3 月 19 日的 Post 记录
const result = await prisma.post.findMany({
where: {
date_created: {
gte: new Date('2020-03-19T14:21:00+0200') /* Includes time offset for UTC */,
},
},
});

contains

n 包含 x

示例

统计所有 content 包含 databasesPost 记录
const result = await prisma.post.count({
where: {
content: {
contains: 'databases',
},
},
});
统计所有 content 包含 databasesPost 记录
const result = await prisma.post.count({
where: {
NOT: {
content: {
contains: 'databases',
},
},
},
});

使用 全文搜索String 字段中搜索。

信息

对于 PostgreSQL,此功能仍在预览中。请启用 fullTextSearchPostgres 功能标志才能使用它。

示例

查找所有标题包含 catdog 的帖子。
const result = await prisma.post.findMany({
where: {
title: {
search: 'cat | dog',
},
},
});
查找所有标题包含 catdog 的帖子。
const result = await prisma.post.findMany({
where: {
title: {
search: 'cat & dog',
},
},
});
查找所有标题不包含 cat 的帖子。
const result = await prisma.post.findMany({
where: {
title: {
search: '!cat',
},
},
});

mode

备注

  • 仅由 PostgreSQL 和 MongoDB 连接器支持

示例

获取所有 title 包含 prisma (不区分大小写) 的 Post 记录
const result = await prisma.post.findMany({
where: {
title: {
contains: 'prisma',
mode: 'insensitive',
},
},
});

startsWith

示例

获取所有 titlePr 开头(例如 Prisma)的 Post 记录
const result = await prisma.post.findMany({
where: {
title: {
startsWith: 'Pr',
},
},
});

endsWith

获取所有 emailprisma.io 结尾的 User 记录

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

AND

所有条件都必须返回 true。或者,将对象列表传递给 where 子句 — 不需要 AND 运算符

示例

获取所有 content 字段包含 PrismapublishedfalsePost 记录
const result = await prisma.post.findMany({
where: {
AND: [
{
content: {
contains: 'Prisma',
},
},
{
published: {
equals: false,
},
},
],
},
});
获取所有 content 字段包含 PrismapublishedfalsePost 记录(无 AND

以下格式返回与上一个示例相同的结果,无需 AND 运算符

const result = await prisma.post.findMany({
where: {
content: {
contains: 'Prisma',
},
published: {
equals: false,
},
},
});
获取所有 title 字段包含 PrismadatabasespublishedfalsePost 记录

以下示例结合了 ORAND

const result = await prisma.post.findMany({
where: {
OR: [
{
title: {
contains: 'Prisma',
},
},
{
title: {
contains: 'databases',
},
},
],
AND: {
published: false,
},
},
});

OR

一个或多个条件必须返回 true

示例

获取所有 title 字段包含 PrismadatabasesPost 记录
const result = await prisma.post.findMany({
where: {
OR: [
{
title: {
contains: 'Prisma',
},
},
{
title: {
contains: 'databases',
},
},
],
},
});
获取所有 title 字段包含 Prismadatabases,但不包含 SQLPost 记录

以下示例结合了 ORNOT

const result = await prisma.post.findMany({
where: {
OR: [
{
title: {
contains: 'Prisma',
},
},
{
title: {
contains: 'databases',
},
},
],
NOT: {
title: {
contains: 'SQL',
},
},
},
});
获取所有 title 字段包含 Prismadatabases,并且 publishedfalsePost 记录

以下示例结合了 ORAND

const result = await prisma.post.findMany({
where: {
OR: [
{
title: {
contains: 'Prisma',
},
},
{
title: {
contains: 'databases',
},
},
],
AND: {
published: false,
},
},
});

NOT

所有条件都必须返回 false

示例

获取所有 title 不包含 SQLPost 记录
const result = await prisma.post.findMany({
where: {
NOT: {
title: {
contains: 'SQL',
},
},
},
});
获取所有 title 字段包含 Prismadatabases 但不包含 SQL,并且相关 User 记录的电子邮件地址不包含 sarahPost 记录
const result = await prisma.post.findMany({
where: {
OR: [
{
title: {
contains: 'Prisma',
},
},
{
title: {
contains: 'databases',
},
},
],
NOT: {
title: {
contains: 'SQL',
},
},
user: {
NOT: {
email: {
contains: 'sarah',
},
},
},
},
include: {
user: true,
},
});

关系过滤器

some

返回所有记录,其中一个或多个(“some”)相关记录与过滤条件匹配。

备注

  • 您可以使用不带参数的 some 来返回至少有一个关系的所有记录

示例

获取所有 User 记录,其中一些帖子提及 Prisma
const result = await prisma.user.findMany({
where: {
post: {
some: {
content: {
contains: "Prisma"
}
}
}
}
}

every

返回所有记录,其中所有(“every”)相关记录都与过滤条件匹配。

示例

获取所有 User 记录,其中所有帖子都已发布
const result = await prisma.user.findMany({
where: {
post: {
every: {
published: true
},
}
}
}

none

返回所有记录,其中零个相关记录与过滤条件匹配。

备注

示例

获取所有没有帖子的 User 记录
const result = await prisma.user.findMany({
where: {
post: {
none: {} // User has no posts
}
}
}
获取所有没有已发布帖子的 User 记录
const result = await prisma.user.findMany({
where: {
post: {
none: {
published: true
}
}
}
}

is

返回所有相关记录与过滤条件匹配的记录(例如,用户名为 is Bob)。

示例

获取所有用户名为 "Bob"Post 记录
const result = await prisma.post.findMany({
where: {
user: {
is: {
name: "Bob"
},
}
}
}

isNot

返回所有相关记录不匹配过滤条件(例如,用户名为 isNot Bob)的记录。

示例

获取所有用户姓名不是 "Bob"Post 记录
const result = await prisma.post.findMany({
where: {
user: {
isNot: {
name: "Bob"
},
}
}
}

标量列表方法

set

使用 set 覆盖标量列表字段的值。

备注

  • set 是可选的 — 您可以直接设置值

    tags: ['computers', 'books'];

示例

tags 的值设置为字符串值列表
const setTags = await prisma.post.update({
where: {
id: 9,
},
data: {
tags: {
set: ['computing', 'books'],
},
},
});
tags 设置为值列表,使用 set 关键字
const setTags = await prisma.post.update({
where: {
id: 9,
},
data: {
tags: ['computing', 'books'],
},
});

tags 的值设置为单个字符串值

const setTags = await prisma.post.update({
where: {
id: 9,
},
data: {
tags: {
set: 'computing',
},
},
});

push

push2.20.0 及更高版本中可用。使用 push一个值或多个值添加到标量列表字段。

备注

  • 仅适用于 PostgreSQL 和 MongoDB。
  • 您可以推送值列表或单个值。

示例

computing 项添加到 tags 列表
const addTag = await prisma.post.update({
where: {
id: 9,
},
data: {
tags: {
push: 'computing',
},
},
});
const addTag = await prisma.post.update({
where: {
id: 9,
},
data: {
tags: {
push: ['computing', 'genetics'],
},
},
});

unset

警告

此方法仅在 MongoDB 3.11.1 及更高版本中可用。

使用 unset 取消设置标量列表的值。与 set: null 不同,unset 完全删除列表。

示例

取消设置 tags 的值
const setTags = await prisma.post.update({
where: {
id: 9,
},
data: {
tags: {
unset: true,
},
},
});

标量列表过滤器

标量列表过滤器允许您按列表/数组字段的内容进行过滤。

警告

适用于

  • PostgreSQL 2.15.0 及更高版本
  • CockroachDB 3.9.0 及更高版本
  • MongoDB 3.11.0 及更高版本

备注

  • 标量列表/数组过滤器 忽略 NULL。使用 isEmptyNOT 不会返回包含 NULL 值列表/数组的记录,并且 { equals: null } 会导致错误。

has

给定值存在于列表中。

示例

以下查询返回所有 tags 列表中包含 "databases"Post 记录

const posts = await client.post.findMany({
where: {
tags: {
has: 'databases',
},
},
});

以下查询返回所有 tags 列表中包含 "databases"Post 记录

const posts = await client.post.findMany({
where: {
NOT: {
tags: {
has: 'databases',
},
},
},
});

hasEvery

每个值都存在于列表中。

示例

以下查询返回所有 tags 列表包含至少 "databases" "typescript"Post 记录

const posts = await prisma.post.findMany({
where: {
tags: {
hasEvery: ['databases', 'typescript'],
},
},
});

hasSome

列表中至少存在一个值。

示例

以下查询返回所有 tags 列表包含 "databases" "typescript"Post 记录

const posts = await prisma.post.findMany({
where: {
tags: {
hasSome: ['databases', 'typescript'],
},
},
});

isEmpty

列表为空。

示例

以下查询返回所有没有标签的 Post 记录

const posts = await prisma.post.findMany({
where: {
tags: {
isEmpty: true,
},
},
});

isSet

警告

此过滤器仅在 MongoDB 3.11.1 及更高版本中可用。

筛选列表以仅包含已设置(已设置为值或显式设置为 null)的结果。将此过滤器设置为 true 将排除根本未设置的未定义结果。

示例

以下查询返回所有 tags 已设置为 null 或值的 Post 记录

const posts = await prisma.post.findMany({
where: {
tags: {
isSet: true,
},
},
});

equals

列表与给定值完全匹配。

示例

以下查询返回所有 tags 列表仅包含 "databases""typescript"Post 记录

const posts = await prisma.post.findMany({
where: {
tags: {
equals: ['databases', 'typescript'],
},
},
});

复合类型方法

警告

仅在 Prisma 3.10.0 及更高版本的 MongoDB 中可用。

复合类型方法允许您创建、更新和删除 复合类型

set

使用 set 覆盖复合类型的值。

备注

  • set 关键字是可选的 — 您可以直接设置值
    photos: [
    { height: 100, width: 200, url: '1.jpg' },
    { height: 100, width: 200, url: '2.jpg' },
    ];

示例

在新 order 中设置 shippingAddress 复合类型
const order = await prisma.order.create({
data: {
// Normal relation
product: { connect: { id: 'some-object-id' } },
color: 'Red',
size: 'Large',
// Composite type
shippingAddress: {
set: {
street: '1084 Candycane Lane',
city: 'Silverlake',
zip: '84323',
},
},
},
});
将可选复合类型设置为 null
const order = await prisma.order.create({
data: {
// Embedded optional type, set to null
billingAddress: {
set: null,
},
},
});

unset

使用 unset 取消设置复合类型的值。与 set: null 不同,这会从 MongoDB 文档中完全删除该字段。

示例

order 中移除 billingAddress
const order = await prisma.order.update({
where: {
id: 'some-object-id',
},
data: {
billingAddress: {
// Unset the billing address
// Removes "billingAddress" field from order
unset: true,
},
},
});

update

使用 update 更新必需复合类型中的字段。

备注

update 方法不能用于可选类型。请改用 upsert

示例

更新 shippingAddress 复合类型的邮政编码字段
const order = await prisma.order.update({
where: {
id: 'some-object-id',
},
data: {
shippingAddress: {
// Update just the zip field
update: {
zip: '41232',
},
},
},
});

upsert

使用 upsert 更新现有可选复合类型(如果存在),否则设置复合类型。

备注

upsert 方法不能用于必需类型。请改用 update

示例

如果 billingAddress 不存在,则创建新的 billingAddress,否则更新它
const order = await prisma.order.update({
where: {
id: 'some-object-id',
},
data: {
billingAddress: {
// Create the address if it doesn't exist,
// otherwise update it
upsert: {
set: {
street: '1084 Candycane Lane',
city: 'Silverlake',
zip: '84323',
},
update: {
zip: '84323',
},
},
},
},
});

push

使用 push 将值推送到复合类型列表的末尾。

示例

将新照片添加到 photos 列表
const product = prisma.product.update({
where: {
id: 10,
},
data: {
photos: {
// Push a photo to the end of the photos list
push: [{ height: 100, width: 200, url: '1.jpg' }],
},
},
});

复合类型过滤器

警告

仅在 Prisma 3.11.0 及更高版本的 MongoDB 中可用。

复合类型过滤器允许您过滤 复合类型 的内容。

equals

使用 equals 通过匹配复合类型或复合类型列表来筛选结果。要求复合类型的所有必需字段都匹配。

备注

匹配可选字段时,您需要区分文档中未定义(缺失)的字段和已显式设置为 null 的字段

  • 如果您省略一个可选字段,它将匹配未定义的字段,但不匹配已设置为 null 的字段
  • 如果您使用 equals: { ... exampleField: null ... } 过滤可选字段的 null 值,那么它将仅匹配已设置为 null 的文档,而不匹配未定义的字段

使用 equals 时,字段和列表的顺序很重要

  • 对于字段,{ "a": "1", "b": "2" }{ "b": "2", "a": "1" } 不被视为相等
  • 对于列表,[ { "a": 1 }, { "a": 2 } ][ { "a": 2 }, { "a": 1 } ] 不被视为相等

示例

查找与给定 shippingAddress 完全匹配的订单
const orders = await prisma.order.findMany({
where: {
shippingAddress: {
equals: {
street: '555 Candy Cane Lane',
city: 'Wonderland',
zip: '52337',
},
},
},
});
查找具有与所有给定 url 匹配的照片的产品
const product = prisma.product.findMany({
where: {
equals: {
photos: [{ url: '1.jpg' }, { url: '2.jpg' }],
},
},
});

is

使用 is 过滤结果,通过匹配复合类型中的特定字段。

示例

查找具有匹配给定街道名称的 shippingAddress 的订单
const orders = await prisma.order.findMany({
where: {
shippingAddress: {
is: {
street: '555 Candy Cane Lane',
},
},
},
});

isNot

使用 isNot 过滤不匹配的复合类型字段结果。

示例

查找 shippingAddress 不匹配给定邮政编码的订单
const orders = await prisma.order.findMany({
where: {
shippingAddress: {
isNot: {
zip: '52337',
},
},
},
});

isEmpty

使用 isEmpty 过滤结果以获取空的复合类型列表。

示例

查找没有照片的产品
const product = prisma.product.findMany({
where: {
photos: {
isEmpty: true,
},
},
});

every

使用 every 过滤复合类型列表,其中列表中的每个项都匹配条件。

示例

查找第一件照片的 height 都为 200 的产品
const product = await prisma.product.findFirst({
where: {
photos: {
every: {
height: 200,
}
}
},
})

some

使用 some 过滤复合类型列表,其中列表中的一个或多个项匹配条件。

示例

查找第一件照片的 url2.jpg 的产品
const product = await prisma.product.findFirst({
where: {
photos: {
some: {
url: "2.jpg",
}
}
},
})

none

使用 none 过滤复合类型列表,其中列表中的任何项都不匹配条件。

示例

查找第一件照片的 url 不为 2.jpg 的产品
const product = await prisma.product.findFirst({
where: {
photos: {
none: {
url: "2.jpg",
}
}
},
})

原子数字操作

更新的原子操作适用于数字字段类型(FloatInt)。此功能允许您根据字段的当前值(例如减去除以)更新字段,而不会冒竞态条件的风险。

概述:竞态条件

当两个或多个操作必须按顺序执行才能完成一项任务时,就会发生竞态条件。在以下示例中,两个客户端尝试将同一字段(postCount)增加一

客户端操作
客户端 1获取字段值21
客户端 2获取字段值21
客户端 2设置字段值22
客户端 1设置字段值22

应该23,但两个客户端未按顺序读取和写入 postCount 字段。更新的原子操作将读取和写入组合成单个操作,从而防止了竞态条件

客户端操作
客户端 1获取并设置字段值2122
客户端 2获取并设置字段值2223

运算符

选项描述
incrementn 添加到当前值。
decrement从当前值中减去 n
multiply将当前值乘以 n
divide将当前值除以 n
set设置当前字段值。与 { myField : n } 相同。

备注

  • 每个查询的每个字段只能执行一次原子更新。
  • 如果字段为 null,则不会被 incrementdecrementmultiplydivide 更新。

示例

将所有 Post 记录的 viewlikes 字段都增加 1

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

将所有 Post 记录的所有 views 字段设置为 0

const updatePosts = await prisma.post.updateMany({
data: {
views: {
set: 0,
},
},
});

也可以写成

const updatePosts = await prisma.post.updateMany({
data: {
views: 0,
},
});

Json 过滤器

有关用例和高级示例,请参阅:使用 Json 字段

警告

PostgreSQLMySQL 支持,path 选项的语法不同。PostgreSQL 不支持对数组中的对象键值进行过滤。

本节中的示例假设 pet 字段的值为

{
"favorites": {
"catBreed": "Turkish van",
"dogBreed": "Rottweiler",
"sanctuaries": ["RSPCA", "Alley Cat Allies"],
"treats": [
{ "name": "Dreamies", "manufacturer": "Mars Inc" },
{ "name": "Treatos", "manufacturer": "The Dog People" }
]
},
"fostered": {
"cats": ["Bob", "Alice", "Svetlana the Magnificent", "Queenie"]
},
"owned": {
"cats": ["Elliott"]
}
}

备注

path

path 表示特定键的位置。以下查询返回所有嵌套 favourites > dogBreed 键等于 "Rottweiler" 的用户。

const getUsers = await prisma.user.findMany({
where: {
pets: {
path: ['favorites', 'dogBreed'],
equals: 'Rottweiler',
},
},
});

以下查询返回所有嵌套 owned > cats 数组包含 "Elliott" 的用户。

const getUsers = await prisma.user.findMany({
where: {
pets: {
path: ['owned', 'cats'],
array_contains: ['Elliott'],
},
},
});
警告

仅 MySQL 连接器支持按数组中对象的键值进行过滤(如下)。

以下查询返回所有嵌套 favorites > treats 数组包含 name 值为 "Dreamies" 的对象的用户

const getUsers = await prisma.user.findMany({
where: {
pets: {
path: '$.favorites.treats[*].name',
array_contains: 'Dreamies',
},
},
});

string_contains

以下查询返回所有嵌套 favorites > catBreed 键值包含 "Van" 的用户

const getUsers = await prisma.user.findMany({
where: {
pets: {
path: ['favorites', 'catBreed'],
string_contains: 'Van',
},
},
});

string_starts_with

以下查询返回所有嵌套 favorites > catBreed 键值以 "Turkish" 开头的用户

const getUsers = await prisma.user.findMany({
where: {
pets: {
path: ['favorites', 'catBreed'],
string_starts_with: 'Turkish',
},
},
});

string_ends_with

以下查询返回所有嵌套 favorites > catBreed 键值以 "Van" 结尾的用户

const getUsers = await prisma.user.findMany({
where: {
pets: {
path: ['favorites', 'catBreed'],
string_ends_with: 'Van',
},
},
});

mode

指定字符串过滤是否应区分大小写(默认)或不区分大小写。

以下查询返回所有嵌套 favorites > catBreed 键值包含 "Van""van" 的用户

const getUsers = await prisma.user.findMany({
where: {
pets: {
path: ['favorites', 'catBreed'],
string_contains: 'Van',
mode: "insensitive",
},
},
});

array_contains

以下查询返回所有 sanctuaries 数组包含值 "RSPCA" 的用户

const getUsers = await prisma.user.findMany({
where: {
pets: {
path: ['sanctuaries'],
array_contains: ['RSPCA'],
},
},
});
信息

在 PostgreSQL 中,array_contains 的值必须是一个数组而不是字符串,即使数组只包含一个值。

以下查询返回所有 sanctuaries 数组包含给定数组中所有值的用户

const getUsers = await prisma.user.findMany({
where: {
pets: {
path: ['sanctuaries'],
array_contains: ['RSPCA', 'Alley Cat Allies'],
},
},
});

array_starts_with

以下查询返回所有 sanctuaries 数组以值 "RSPCA" 开头的用户

const getUsers = await prisma.user.findMany({
where: {
pets: {
path: ['sanctuaries'],
array_starts_with: 'RSPCA',
},
},
});

array_ends_with

以下查询返回所有 sanctuaries 数组以值 "Alley Cat Allies" 结尾的用户

const getUsers = await prisma.user.findMany({
where: {
pets: {
path: ['sanctuaries'],
array_ends_with: 'Alley Cat Allies',
},
},
});

客户端方法

注意: 客户端级别的方法以 $ 为前缀。

备注

  • 使用 $extends 扩展的客户端实例上不存在 $on$use 客户端方法
警告

扩展客户端中,客户端方法不一定存在。如果您正在扩展您的客户端,请在使用 $transaction$connect 等客户端方法之前检查其是否存在。

此外,如果您正在使用 $on$use,则需要在扩展客户端之前使用这些客户端方法,因为这些方法在扩展客户端上不存在。对于 $use,我们特别建议转换为使用查询扩展

$disconnect()

$disconnect() 方法关闭调用 $connect 时建立的数据库连接,并停止运行 Prisma ORM 查询引擎的进程。有关 $connect()$disconnect() 的概述,请参阅连接管理

备注

  • $disconnect() 返回一个 Promise,因此您应该在 async 函数中使用 await 关键字调用它。

$connect()

$connect() 方法通过 Prisma ORM 的查询引擎建立与数据库的物理连接。有关 $connect()$disconnect() 的概述,请参阅连接管理

备注

  • $connect() 返回一个 Promise,因此您应该在 async 函数中使用 await 关键字调用它。

$on()

警告

$on扩展客户端中不可用。请迁移到客户端扩展,或者在扩展客户端之前使用 $on 方法。

$on() 方法允许您订阅日志事件退出钩子

$queryRawTyped

请参阅:使用原始 SQL ($queryRawTyped)

$queryRaw

请参阅:使用原始 SQL ($queryRaw)

$queryRawUnsafe()

请参阅:使用原始 SQL ($queryRawUnsafe())

$executeRaw

请参阅:使用原始 SQL ($executeRaw)

$executeRawUnsafe()

请参阅:使用原始 SQL ($executeRawUnsafe())

$runCommandRaw()

请参阅:使用原始 SQL ($runCommandRaw())

$transaction()

请参阅:事务

$extends

使用 $extends,您可以创建并使用 Prisma Client 扩展,以以下方式为 Prisma Client 添加功能

  • model:为您的模型添加自定义方法
  • client:为您的客户端添加自定义方法
  • query:创建自定义 Prisma Client 查询
  • result:为您的查询结果添加自定义字段

了解更多:Prisma Client 扩展

实用工具类型

实用工具类型是存在于 Prisma 命名空间上的辅助函数和类型。它们对于保持应用程序类型安全很有用。

Prisma.validator

validator 帮助您根据您的模式模型创建可重用的查询参数,同时确保您创建的对象有效。另请参阅:使用 Prisma.validator

您可以通过两种方式使用 validator

使用生成的 Prisma 客户端类型

使用类型提供了一种类型级别的验证数据的方法

Prisma.validator<GeneratedType>({ args });

使用“选择器”

当使用选择器模式时,您使用现有的 Prisma Client 实例来创建一个验证器。此模式允许您选择模型、操作和查询选项以进行验证。

您还可以使用已通过Prisma Client 扩展进行扩展的 Prisma Client 实例。

Prisma.validator(PrismaClientInstance, '<model>', '<operation>', '<query option>')({ args });

示例

以下示例展示了如何提取和验证可在应用程序中重用的 create 操作的输入

import { Prisma } from '../prisma/generated/client';

const validateUserAndPostInput = (name, email, postTitle) => {
return Prisma.validator<Prisma.UserCreateInput>()({
name,
email,
posts: {
create: {
title: postTitle,
},
},
});
};

这是相同操作的另一种语法

import { Prisma } from '../prisma/generated/client';
import prisma from './prisma';

const validateUserAndPostInput = (name, email, postTitle) => {
return Prisma.validator(
prisma,
'user',
'create',
'data'
)({
name,
email,
posts: {
create: {
title: postTitle,
},
},
});
};

比较同一表中的列

您可以直接比较同一表中的列,以进行非唯一过滤。

此功能在版本 5.0.0 中已全面推出,并可通过 Prisma ORM 4.3.0 到 4.16.2 版本的 fieldReference 预览功能使用。

信息

在以下情况下,您必须使用原始查询比较同一表中的列

  • 如果您使用的版本早于 4.3.0
  • 如果您想使用唯一过滤器,例如findUniquefindUniqueOrThrow
  • 如果您想将字段与唯一约束进行比较
  • 如果您想使用以下运算符之一来比较 MySQL 或 MariaDB 中的JSON 字段与另一个字段:gtgteltlte。请注意,您可以使用这些运算符将 JSON 字段与标量值进行比较。此限制仅适用于您尝试将 JSON 字段与另一个字段进行比较的情况。

要比较同一表中的列,请使用 <model>.fields 属性。在以下示例中,查询返回 prisma.product.quantity 字段中的值小于或等于 prisma.product.warnQuantity 字段中的值的所有记录。

prisma.product.findMany({
where: { quantity: { lte: prisma.product.fields.warnQuantity } },
});
信息

fields 是每个模型的特殊属性。它包含该模型的字段列表。

注意事项

字段必须是相同类型

您只能对相同类型的字段进行比较。例如,以下代码会导致错误

await prisma.order.findMany({
where: {
id: { equals: prisma.order.fields.due },
// ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
// Type error: id is a string, while amountDue is an integer
},
});

字段必须在同一个模型中

您只能对同一模型中的字段使用 fields 属性进行比较。以下示例不起作用

await prisma.order.findMany({
where: {
id: { equals: prisma.user.fields.name },
// ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
// Type error: name is a field on the User model, not Order
},
});

但是,您可以使用标准查询比较不同模型中的字段。

groupBy 模型查询中,将您引用的字段放入 by 参数中

如果您使用带有 having 选项的groupBy模型查询,则必须将您引用的字段放入 by 参数中。

以下示例有效

prisma.user.groupBy({
by: ['id', 'name'],
having: { id: { equals: prisma.user.fields.name } },
});

以下示例无效,因为 name 不在 by 参数中

prisma.user.groupBy({
by: ['id'],
having: { id: { equals: prisma.user.fields.name } },
// ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
// name is not in the 'by' argument
});

在标量列表中搜索字段

如果您的数据源支持标量列表(例如在 PostgreSQL 中),则可以搜索特定字段在字段列表中的所有记录。为此,请使用innotIn过滤器引用标量列表。例如

await prisma.user.findMany({
where: {
// find all users where 'name' is in a list of tags
name: { in: prisma.user.fields.tags },
},
});

使用 UserWhereUniqueInput 过滤非唯一字段

从版本 5.0.0 开始,where 上生成的类型 UserWhereUniqueInput 公开了模型上的所有字段,而不仅仅是唯一字段。这在版本 4.5.0 到 4.16.2 之间的 extendedWhereUnique 预览标志下可用。

您必须在布尔运算符之外where 语句中至少指定一个唯一字段,并且可以指定任意数量的附加唯一和非唯一字段。您可以使用此功能为返回单个记录的任何操作添加过滤器。例如,您可以将此功能用于以下目的

从版本 4.6.0 开始,您可以使用此功能过滤可选的一对一嵌套读取

更新的乐观并发控制

您可以过滤非唯一字段,以对 update 操作执行乐观并发控制

为了执行乐观并发控制,我们建议您使用 version 字段来检查记录或相关记录中的数据在代码执行期间是否发生更改。在 4.5.0 版本之前,您无法在 update 操作中评估 version 字段,因为该字段是非唯一的。从 4.5.0 版本开始,您可以评估 version 字段。

在以下示例中,updateOneupdateTwo 首先读取相同的记录,然后尝试更新它。数据库仅在 version 中的值与初始读取时的值相同时才执行这些更新。当数据库执行这些更新中的第一个(可能是 updateOneupdateTwo,取决于时间)时,它会递增 version 中的值。这意味着数据库不会执行第二个更新,因为 version 中的值已更改。

model User {
id Int @id @default(autoincrement())
email String @unique
city String
version Int
}
function updateOne() {
const user = await prisma.user.findUnique({ id: 1 });

await prisma.user.update({
where: { id: user.id, version: user.version },
data: { city: 'Berlin', version: { increment: 1 } },
});
}

function updateTwo() {
const user = await prisma.user.findUnique({ id: 1 });

await prisma.user.update({
where: { id: user.id, version: user.version },
data: { city: 'New York', version: { increment: 1 } },
});
}

function main() {
await Promise.allSettled([updateOne(), updateTwo()]);
}

权限检查

您可以在更新期间过滤非唯一字段以检查权限。

在以下示例中,用户想要更新帖子标题。where 语句检查 authorId 中的值以确认用户是该帖子的作者。应用程序仅在用户是帖子作者时才更新帖子标题。

await prisma.post.update({
where: { id: 1, authorId: 1 },
data: { title: 'Updated post title' },
});

软删除

您可以过滤非唯一字段以处理软删除。

在以下示例中,如果帖子被软删除,我们不希望返回该帖子。该操作仅在 isDeleted 中的值为 false 时才返回该帖子。

prisma.Post.findUnique({ where: { id: postId, isDeleted: false } });

UserWhereUniqueInput 考虑事项

带有 UserWhereUniqueInput 的布尔运算符

使用 UserWhereUniqueInput,您必须在布尔运算符 ANDORNOT 之外指定至少一个唯一字段。您仍然可以将这些布尔运算符与过滤器中的任何其他唯一字段或非唯一字段结合使用。

在以下示例中,我们测试了唯一字段 idemail 的结合。这是有效的。

await prisma.user.update({
where: { id: 1, OR: [{ email: "bob@prisma.io" }, { email: "alice@prisma.io" }] },
// ^^^ Valid: the expression specifies a unique field (`id`) outside of any boolean operators
data: { ... }
})

// SQL equivalent:
// WHERE id = 1 AND (email = "bob@prisma.io" OR email = "alice@prisma.io")

以下示例无效,因为没有任何布尔运算符之外的唯一字段

await prisma.user.update({
where: { OR: [{ email: "bob@prisma.io" }, { email: "alice@prisma.io" }] },
// ^^^ Invalid: the expressions does not contain a unique field outside of boolean operators
data: { ... }
})

一对一关系

从版本 4.5.0 开始,您可以在一对一关系的以下操作中过滤非唯一字段

  • 嵌套更新
  • 嵌套更新或插入
  • 嵌套断开连接
  • 嵌套删除

Prisma Client 自动使用唯一过滤器来选择适当的相关记录。因此,您不需要在带有 WhereUniqueInput 生成类型where 语句中指定唯一过滤器。相反,where 语句具有 WhereInput 生成类型。您可以使用它进行过滤,而不受 WhereUniqueInput 的限制。

嵌套更新示例
await prisma.user.update({
where: { id: 1, },
data: {
to_one: {
// Before Prisma version 4.5.0
update: { field: "updated" }
// From Prisma version 4.5.0, you can also do the following:
update: { where: { /*WhereInput*/ }, data: { field: "updated" } } }
}
}
})
嵌套更新或插入示例
await prisma.user.update({
where: { id: 1, },
data: {
to_one: {
upsert: {
where: { /* WhereInput */ } // new argument from Prisma 4.5.0
create: { /* CreateInput */ },
update: { /* CreateInput */ },
}
}
}
})
嵌套断开连接示例
await prisma.user.update({
where: { id: 1, },
data: {
to_one: {
// Before Prisma version 4.5.0
disconnect: true
// From Prisma version 4.5.0, you can also do the following:
disconnect: { /* WhereInput */ }
}
}
})
嵌套删除示例
await prisma.user.update({
where: { id: 1, },
data: {
to_one: {
// Before Prisma version 4.5.0
delete: true
// From Prisma version 4.5.0, you can also do the following:
delete: { /* WhereInput */ }
}
}
})

PrismaPromise 行为

所有 Prisma Client 查询都返回 PrismaPromise 实例。这是一个“thenable”,这意味着 PrismaPromise 仅在您调用 await.then().catch() 时才执行。此行为与常规 JavaScript Promise 不同,后者会立即开始执行。

例如

const findPostOperation = prisma.post.findMany({}); // Query not yet executed

findPostOperation.then(); // Prisma Client now executes the query
// or
await findPostOperation; // Prisma Client now executes the query

使用 $transaction API 时,此行为使 Prisma Client 可以将所有查询作为单个事务传递给查询引擎。

© . This site is unofficial and not affiliated with Prisma Data, Inc.