跳到主要内容

Prisma Client API 参考

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/client';

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

基于以下 datasource

datasource db {
provider = "sqlite"
url = env("DATABASE_URL")
}

datasourceUrl

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

属性

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

示例

import { PrismaClient } from '@prisma/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错误。
Emit 格式
名称描述
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 字段将未定义。

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

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

示例

queryinfo 记录到 stdout
import { PrismaClient } from '@prisma/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/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/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 返回的错误的级别和格式。

错误格式

名称描述
未定义如果未定义,则默认为无颜色。
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 功能标志之后。

示例

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

import { Pool, neonConfig } from '@neondatabase/serverless';
import { PrismaNeon } from '@prisma/adapter-neon';
import { PrismaClient } from '@prisma/client';
import dotenv from 'dotenv';
import ws from 'ws';

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

const pool = new Pool({ connectionString });
const adapter = new PrismaNeon(pool);
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,
},
});
获取 email[email protected]User 记录
const result = await prisma.user.findUnique({
where: {
email: '[email protected]',
},
});
获取 firstNameAlicelastNameSmithUser 记录 (@@unique)
展开以查看带有 @@unique 块的示例 User 模型
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)
展开以查看带有 @@id 块的示例 User 模型
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/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 确定要返回哪些字段。
空数组[]未找到匹配的记录。

示例

有关如何过滤结果的示例,请参见 过滤器条件和运算符

获取 nameAlice 的所有 User 记录
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: '[email protected]' },
});
创建多个新记录

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

以下示例导致 两个 INSERT 语句

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

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

async function main() {
let users: Prisma.UserCreateInput[] = [
{
email: '[email protected]',
name: 'Ari',
profileViews: 20,
coinflips: [true, false, false],
role: 'ADMIN',
},
{
email: '[email protected]',
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 确定要返回哪些字段。
RecordNotFound 异常如果记录不存在,则抛出异常。

备注

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

示例

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

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 查询移交给数据库。 了解更多

示例

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

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: '[email protected]',
},
update: {
email: '[email protected]',
},
});

在这种情况下,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: '[email protected]',
},
update: {
email: '[email protected]',
},
});

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

prisma.User.upsert({
where: {
userName: 'Alice',
},
create: {
id: 1,
profileViews: 1,
userName: 'AliceS',
email: '[email protected]',
},
update: {
email: '[email protected]',
},
});

在以下查询中,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: '[email protected]',
},
update: {
email: '[email protected]',
},
});

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 来确定要返回的字段。
RecordNotFound 异常如果记录不存在,则抛出异常。

备注

  • 要基于某些条件删除多个记录(例如,所有 email 地址为 prisma.ioUser 记录,请使用 deleteMany)。

示例

删除 id1User 记录
const user = await prisma.user.delete({
where: { id: 1 },
});
删除 email 等于 [email protected]User 记录

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

const deleteUser = await prisma.user.delete({
where: {
email: '[email protected]',
},
select: {
email: true,
name: true,
},
});
显示CLI结果
{ "email": "[email protected]", "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: '[email protected]' },
{ name: 'Alex', email: '[email protected]' },
],
});

createManyAndReturn()

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

信息

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

选项

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

备注

  • SQLite 不支持 skipDuplicates 选项。
  • 不能通过在顶级 createManyAndReturn() 查询中使用嵌套的 createcreateManyconnectconnectOrCreate 查询来创建或连接关系。有关解决方法,请参见此处。
  • 当通过 include 包含关系时,每个关系都会生成一个单独的查询。
  • 不支持 relationLoadStrategy: join

返回类型

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

示例

创建并返回多个新用户
const users = await prisma.user.createManyAndReturn({
data: [
{ name: 'Sonali', email: '[email protected]' },
{ name: 'Alex', email: '[email protected]' },
],
})
显示CLI结果
[
{ "id": 0, "name": "Sonali", "email": "[email protected]", "profileViews": 0 },
{ "id": 1, "name": "Alex", "email": "[email protected]", "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' },
});
更新所有 email 包含 prisma.io 且至少一篇相关 Post 拥有超过 10 个赞的 User 记录
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": "[email protected]", "role": "ADMIN", "profileViews": 0 },
{ "id": 1, "name": "Alex", "email": "[email protected]", "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.ioUser 记录,但限制为删除 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();
统计至少有一篇已发布 Post 的所有 User 记录
const result = await prisma.user.count({
where: {
post: {
some: {
published: true,
},
},
},
});
使用 select 执行三个单独的计数

以下查询返回:

  • 所有记录的计数 (_all)
  • 所有 name 字段为非 null 的记录的计数
  • 所有 city 字段为非 null 的记录的计数
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 记录的计数,以及每个组中 city 字段值为非 null 的所有记录的计数。

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结果
include 内部的 select
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: '[email protected]',
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 中正式发布 (General Availability)。它通过 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预览 移至 正式发布 (General Availability)join 将普遍成为所有关系查询的默认设置。

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

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

generator client {
provider = "prisma-client-js"
previewFeatures = ["relationJoins"]
}

添加此标志后,您需要再次运行 prisma generate 以重新生成 Prisma Client。此功能目前在 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: '[email protected]',
    },
    },
    ],
    });
  • UserWhereUniqueInput 此类型通过公开模型上的任何唯一字段来工作。分配了 @id 的字段被认为是唯一的,分配了 @unique 的字段也是如此。

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

    // UserWhereUniqueInput
    const whereEmailIsUnique = Prisma.validator<Prisma.UserWhereUniqueInput>()({
    email: '[email protected]',
    })
  • 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 - 此类型将更新 id 匹配的 Post 记录的 title 字段,如果不存在,则会创建它。

    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 - 此类型将更新所有 published 设置为 false 的 Post 记录。

    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 值进行排序,了解如何启用该功能的详细信息。
名称描述
first先按 null 值排序。
last后按 null 值排序。

示例

email 字段对 User 进行排序

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

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

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

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

按相关联的 User 记录的 name 字段对 Post 进行排序

以下查询按用户名对帖子进行排序

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

按相关联的 User 记录的 name 字段对 Post 进行排序,并将 null 记录排在最前面

以下查询按用户名对帖子进行排序,并将 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',
},
},
});
按多个字段(email role)对 User 进行排序

以下示例按两个字段对用户进行排序 - 首先是 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结果
emailUser 进行排序,选择 nameemail

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

const users3 = await prisma.user.findMany({
orderBy: {
email: 'asc',
},
select: {
name: true,
email: true,
},
});
显示CLI结果
emailUser 记录进行排序,并按 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 中删除重复的记录列表。另请参阅:聚合、分组和汇总

示例

在单个字段上选择不同的值

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

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

以下示例返回所有不同的 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' },
];

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

将不同的值选择与过滤器结合使用

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

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

嵌套查询

create

嵌套的 create 查询向父记录添加新的相关记录或记录集。请参阅:使用关联关系

备注

  • 当您 create() (prisma.user.create(...)) 新的父记录或 update() (prisma.user.update(...)) 现有父记录时,create 可用作嵌套查询。
  • 您可以使用嵌套的 create 嵌套的 createMany 来创建多个相关记录。如果您需要 skipDuplicates 查询选项,则应使用 createMany

示例

创建一个新的 User 记录和一个新的 Profile 记录
const user = await prisma.user.create({
data: {
email: '[email protected]',
profile: {
create: { bio: 'Hello World' },
},
},
});
创建一个新的 Profile 记录和一个新的 User 记录
const user = await prisma.profile.create({
data: {
bio: 'Hello World',
user: {
create: { email: '[email protected]' },
},
},
})
创建一个新的 User 记录和一个新的 Post 记录
const user = await prisma.user.create({
data: {
email: '[email protected]',
posts: {
create: { title: 'Hello World' },
},
},
});
创建一个新的 User 记录和两个新的 Post 记录

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

const user = await prisma.user.create({
data: {
email: '[email protected]',
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: '[email protected]' },
data: {
profile: {
create: { bio: 'Hello World' },
},
},
});
通过创建一个新的 Post 记录来更新现有的 User 记录
const user = await prisma.user.update({
where: { email: '[email protected]' },
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 记录列表。请参阅:使用关联关系

示例

通过断开任何先前的 Post 记录并连接其他两个现有记录来更新现有的 User 记录
const user = await prisma.user.update({
where: { email: '[email protected]' },
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 时,它们应用的顺序会显著影响结果。 如果在 connect 之前使用 set,则连接的记录将仅反映 connect 操作建立的最终状态,因为 set 会在 connect 建立新连接之前清除所有现有连接。 相反,如果在 set 之前应用 connect,则 set 操作将通过清除所有连接的记录并用其自身指定的状态替换它们来覆盖 connect 操作。

示例

创建一个新的 Profile 记录,并通过唯一字段将其连接到现有的 User 记录
const user = await prisma.profile.create({
data: {
bio: 'Hello World',
user: {
connect: { email: '[email protected]' },
},
},
});
创建一个新的 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: '[email protected]' },
},
},
});
通过将现有的 User 记录连接到现有的 Profile 记录来更新它
const user = await prisma.user.update({
where: { email: '[email protected]' },
data: {
profile: {
connect: { id: 24 },
},
},
});
通过将现有的 User 记录连接到两个现有的 Post 记录来更新它
const user = await prisma.user.update({
where: { email: '[email protected]' },
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. 尝试将 profile 连接到电子邮件地址为 [email protected]User
  3. 如果匹配的用户不存在,则创建一个新用户
const user = await prisma.profile.create({
data: {
bio: 'The coolest Alice on the planet',
user: {
connectOrCreate: {
where: { email: '[email protected]' },
create: { email: '[email protected]'}
},
},
})
创建一个新的 Post 记录,并将其连接到现有的 User 记录,创建一个新的 User
const user = await prisma.post.create({
data: {
title: 'Hello World',
author: {
connectOrCreate: {
where: { email: '[email protected]' },
create: { email: '[email protected]' },
},
},
},
});
通过将现有的 User 记录连接到现有的 Profile 记录,创建一个新的 Profile 记录来更新它

以下示例

  1. 尝试将用户连接到 id20Profile
  2. 如果匹配的 profile 不存在,则创建一个新的 profile
const updateUser = await prisma.user.update({
where: { email: '[email protected]' },
data: {
profile: {
connectOrCreate: {
where: { id: 20 },
create: {
bio: 'The coolest Alice in town',
},
},
},
},
});
通过将现有的 User 记录连接到两个现有的 Post 记录,或创建两个新的 Post 记录来更新它
const user = await prisma.user.update({
where: { email: '[email protected]' },
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: '[email protected]' },
data: {
profile: {
disconnect: true,
},
},
});
通过断开与其连接的两个 Post 记录来更新现有的 User 记录
const user = await prisma.user.update({
where: { email: '[email protected]' },
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: '[email protected]' },
data: {
profile: {
update: { bio: 'Hello World' },
},
},
});
通过更新与其连接的两个 Post 记录来更新现有的 User 记录
const user = await prisma.user.update({
where: { email: '[email protected]' },
data: {
posts: {
update: [
{
data: { published: true },
where: { id: 32 },
},
{
data: { published: true },
where: { id: 23 },
},
],
},
},
});

upsert

信息

本节介绍在 update() 中使用嵌套的 upsert。要了解有关 upsert() 操作的信息,请参考链接的文档。

嵌套的 upsert 查询更新相关的记录(如果存在),或者创建新的相关记录。

示例

通过更新与其连接的 Profile 记录或创建新的记录(upsert)来更新现有的 User 记录
const user = await prisma.user.update({
where: { email: '[email protected]' },
data: {
profile: {
upsert: {
create: { bio: 'Hello World' },
update: { bio: 'Hello World' },
},
},
},
});
通过更新与其连接的两个 Post 记录或创建新的记录(upsert)来更新现有的 User 记录
const user = await prisma.user.update({
where: { email: '[email protected]' },
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: '[email protected]' },
data: {
profile: {
delete: true,
},
},
});
通过删除与其连接的两个 Post 记录来更新现有的 User 记录
const user = await prisma.user.update({
where: { email: '[email protected]' },
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: {},
},
},
});

过滤器条件和运算符

信息
  • 从 4.3.0 版本开始,您还可以使用这些运算符来比较同一模型中的字段 使用 <model>.fields 属性
  • 在 4.3.0 之前的版本中,您可以使用原始查询来比较同一模型中的字段。

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

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 小于 9 的所有 Post 记录
const getPosts = await prisma.post.findMany({
where: {
likes: {
lt: 9,
},
},
});

lte

n 小于等于 x

示例

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

gt

n 大于 x

示例

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

gte

n 大于等于 x

示例

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

示例

获取所有 Post 记录,其中 date_created 大于 2020 年 3 月 19 日
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

示例

计数所有 Post 记录,其中 content 包含 databases
const result = await prisma.post.count({
where: {
content: {
contains: 'databases',
},
},
});
计数所有 Post 记录,其中 content 包含 databases
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 连接器支持

示例

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

startsWith

示例

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

endsWith

获取所有 User 记录,其中 emailprisma.io 结尾

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

AND

所有条件都必须返回 true。 或者,将对象列表传递到 where 子句中 - AND 运算符不是必需的

示例

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

以下格式返回与前一个示例相同的结果,没有 AND 运算符

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

以下示例结合了 ORAND

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

OR

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

示例

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

以下示例结合了 ORNOT

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

以下示例结合了 ORAND

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

NOT

所有条件都必须返回 false

示例

获取所有 Post 记录,其中 title 不包含 SQL
const result = await prisma.post.findMany({
where: {
NOT: {
title: {
contains: 'SQL',
},
},
},
});
获取所有 Post 记录,其中 title 字段包含 Prismadatabases,但不包含 SQL,并且相关的 User 记录的电子邮件地址不包含 sarah
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)。

示例

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

isNot

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

示例

获取所有 Post 记录,其中用户的名字不是 "Bob"
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'],
},
},
});
使用 set 关键字将 tags 设置为值列表
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。
  • 您可以推送值列表或仅推送单个值。

示例

tags 列表添加 computing
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 复合类型的 zip 字段
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(如果它不存在),否则更新它
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 列表中的所有 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 过滤复合类型列表,其中列表中的每个项目都与条件匹配

示例

查找每张照片的 height200 的第一个产品
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 过滤复合类型列表,其中列表中没有项目与条件匹配。

示例

查找没有照片的 url2.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,因此您应该在带有 await 关键字的 async 函数中调用它。

$connect()

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

备注

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

$on()

警告

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

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

$use()

警告

$use扩展客户端中不可用。请迁移到查询扩展或在扩展客户端之前使用 $use 方法。

$use() 方法添加中间件

prisma.$use(async (params, next) => {
console.log('This is middleware!');
// Modify or interrogate params here

return next(params);
});

next

next 表示中间件堆栈中的“下一层”,根据您在堆栈中的位置,这可能是下一个中间件或 Prisma 查询。

params

params 是一个对象,其中包含要在中间件中使用的信息。

参数描述
action查询类型 - 例如,createfindMany
args传递到查询中的参数 - 例如,wheredataorderBy
dataPath如果您使用fluent API,则会填充此项。
model模型类型 - 例如,PostUser
runInTransaction如果查询在事务的上下文中运行,则返回 true
提示

如果您需要字符串格式的 model 属性,请使用:String(params.model)

参数值示例

{
args: { where: { id: 15 } },
dataPath: [ 'select', 'author', 'select', 'posts' ],
runInTransaction: false,
action: 'findMany',
model: 'Post'
}

示例

请参阅中间件示例

$queryRawTyped

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

$queryRaw

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

$queryRawUnsafe()

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

$executeRaw

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

$executeRawUnsafe()

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

$runCommandRaw()

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

$transaction()

请参阅:事务

$metrics

Prisma Client 指标使您可以详细了解 Prisma Client 如何与您的数据库交互。您可以使用此洞察来帮助诊断应用程序的性能问题。了解更多信息:指标

Prisma Client 指标具有以下方法

$extends

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

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

了解更多信息:Prisma Client 扩展

实用程序类型

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

Prisma.validator

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

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

使用生成的 Prisma Client 类型

使用类型提供了一种类型级别的途径来验证数据

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

使用“选择器”

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

您还可以使用已使用Prisma Client 扩展扩展的 Prisma Client 实例。

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

示例

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

import { Prisma } from '@prisma/client';

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

以下是相同操作的替代语法

import { Prisma } from '@prisma/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 参数中

如果您将 groupBy 模型查询与 having 选项一起使用,则必须将您引用的字段放在 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 之外至少指定一个唯一字段。您仍然可以将这些布尔运算符与过滤器中的任何其他唯一字段或非唯一字段结合使用。

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

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

// SQL equivalent:
// WHERE id = 1 AND (email = "[email protected]" OR email = "[email protected]")

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

await prisma.user.update({
where: { OR: [{ email: "[email protected]" }, { email: "[email protected]" }] },
// ^^^ 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 可以将所有查询作为单个事务传递到查询引擎。