跳到主要内容

原始查询

警告

在 Prisma ORM 5.19.0 版本中,我们发布了 TypedSQL。TypedSQL 是一种编写 SQL 查询的新方法,它类型安全,并且更容易添加到您的工作流程中。

我们强烈建议尽可能使用 TypedSQL 查询,而不是下面描述的旧式原始查询。

Prisma Client 支持向您的数据库发送原始查询的选项。在以下情况下,您可能希望使用原始查询:

  • 您想要运行一个高度优化的查询
  • 您需要 Prisma Client 尚未支持的功能(请考虑提出 issue

原始查询适用于 Prisma ORM 支持的所有关系型数据库。此外,从 3.9.0 版本开始,MongoDB 也支持原始查询。有关更多详细信息,请参阅相关章节

关系型数据库的原始查询

对于关系型数据库,Prisma Client 公开了四种方法,允许您发送原始查询。您可以使用

  • $queryRaw 返回实际记录(例如,使用 SELECT)。
  • $executeRaw 返回受影响行数的计数(例如,在 UPDATEDELETE 之后)。
  • $queryRawUnsafe 使用原始字符串返回实际记录(例如,使用 SELECT)。
  • $executeRawUnsafe 使用原始字符串返回受影响行数的计数(例如,在 UPDATEDELETE 之后)。

名称中带有 "Unsafe" 的方法更加灵活,但存在使您的代码容易受到 SQL 注入攻击的重大风险

其他两种方法可以安全地与简单的模板标签一起使用,无需字符串构建和连接。但是,对于更复杂的用例,需要谨慎,因为如果以某些方式使用这些方法,仍然可能引入 SQL 注入。有关更多详细信息,请参阅下面的SQL 注入预防部分。

注意:上面列表中的所有方法一次只能运行一个查询。您不能附加第二个查询 - 例如,使用 select 1; select 2; 调用它们中的任何一个都将不起作用。

$queryRaw

$queryRaw 返回实际的数据库记录。例如,以下 SELECT 查询返回 User 表中每条记录的所有字段

const result = await prisma.$queryRaw`SELECT * FROM User`;

该方法实现为标记模板,它允许您传递模板字面量,您可以在其中轻松插入您的变量。反过来,Prisma Client 会创建预处理语句,这些语句可以防止 SQL 注入

const email = "[email protected]";
const result = await prisma.$queryRaw`SELECT * FROM User WHERE email = ${email}`;

您还可以使用 Prisma.sql 辅助函数,实际上,$queryRaw 方法只接受模板字符串或 Prisma.sql 辅助函数

const email = "[email protected]";
const result = await prisma.$queryRaw(Prisma.sql`SELECT * FROM User WHERE email = ${email}`);
警告

如果您使用字符串构建将不受信任的输入合并到传递给此方法的查询中,那么您就打开了 SQL 注入攻击的可能性。SQL 注入攻击可能会使您的数据暴露于修改或删除的风险。首选机制是在您运行此方法时包含查询的文本。有关此风险以及如何预防它的示例的更多信息,请参阅下面的SQL 注入预防部分。

注意事项

请注意

  • 模板变量不能在 SQL 字符串字面量内部使用。例如,以下查询将不起作用

    const name = "Bob";
    await prisma.$queryRaw`SELECT 'My name is ${name}';`;

    相反,您可以将整个字符串作为变量传递,或者使用字符串连接

    const name = "My name is Bob";
    await prisma.$queryRaw`SELECT ${name};`;
    const name = "Bob";
    await prisma.$queryRaw`SELECT 'My name is ' || ${name};`;
  • 模板变量只能用于数据值(例如上面示例中的 email)。变量不能用于标识符,例如列名、表名或数据库名,或用于 SQL 关键字。例如,以下两个查询将不起作用

    const myTable = "user";
    await prisma.$queryRaw`SELECT * FROM ${myTable};`;
    const ordering = "desc";
    await prisma.$queryRaw`SELECT * FROM Table ORDER BY ${ordering};`;
  • Prisma 将 $queryRaw$queryRawUnsafe 返回的任何数据库值映射到它们对应的 JavaScript 类型。了解更多

  • $queryRaw 不支持 PostgreSQL 数据库中的动态表名。了解更多

返回类型

$queryRaw 返回一个数组。每个对象对应一个数据库记录

[
{ id: 1, email: "[email protected]", name: "Emelie" },
{ id: 2, email: "[email protected]", name: "Yin" },
]

您还可以$queryRaw 的结果指定类型

签名

$queryRaw<T = unknown>(query: TemplateStringsArray | Prisma.Sql, ...values: any[]): PrismaPromise<T>;

$queryRaw 结果指定类型

PrismaPromise<T> 使用泛型类型参数 T。您可以在调用 $queryRaw 方法时确定 T 的类型。在以下示例中,$queryRaw 返回 User[]

// import the generated `User` type from the `@prisma/client` module
import { User } from "@prisma/client";

const result = await prisma.$queryRaw<User[]>`SELECT * FROM User`;
// result is of type: `User[]`

注意:如果您不提供类型,$queryRaw 默认使用 unknown 类型。

如果您正在选择模型的特定字段或想要包含关联关系,请参阅关于利用 Prisma Client 生成类型的文档,以确保结果类型正确。

使用原始 SQL 时的类型注意事项

当您为 $queryRaw 的结果指定类型时,原始数据可能并不总是与建议的 TypeScript 类型匹配。例如,以下 Prisma 模型包含一个名为 publishedBoolean 字段

model Post {
id Int @id @default(autoincrement())
published Boolean @default(false)
title String
content String?
}

以下查询返回所有帖子。然后,它打印出每个 Postpublished 字段的值

const result = await prisma.$queryRaw<Post[]>`SELECT * FROM Post`;

result.forEach((x) => {
console.log(x.published);
});

对于常规 CRUD 查询,Prisma Client 查询引擎标准化了所有数据库的返回类型。使用原始查询则不然。如果数据库提供商是 MySQL,则返回的值为 10。但是,如果数据库提供商是 PostgreSQL,则值为 truefalse

注意:Prisma 将 JavaScript 整数作为 INT8 发送到 PostgreSQL。这可能会与您只接受 INT4 作为输入的用户自定义函数冲突。如果您将 $queryRaw 与 PostgreSQL 数据库结合使用,请将输入类型更新为 INT8,或将查询参数强制转换为 INT4

PostgreSQL 中的动态表名

无法内插表名。这意味着您不能将动态表名与 $queryRaw 一起使用。相反,您必须使用 $queryRawUnsafe,如下所示

let userTable = "User";
let result = await prisma.$queryRawUnsafe(`SELECT * FROM ${userTable}`);

请注意,如果您将 $queryRawUnsafe 与用户输入结合使用,您将面临 SQL 注入攻击的风险。了解更多

$queryRawUnsafe()

$queryRawUnsafe() 方法允许您将原始字符串(或模板字符串)传递到数据库。

警告

如果您将此方法与用户输入一起使用(换句话说,SELECT * FROM table WHERE columnx = ${userInput}),那么您就打开了 SQL 注入攻击的可能性。SQL 注入攻击可能会使您的数据暴露于修改或删除的风险。

在任何可能的情况下,您都应该使用 $queryRaw 方法。当正确使用时,$queryRaw 方法会更安全,但请注意,在某些情况下,$queryRaw 方法也可能变得易受攻击。有关更多信息,请参阅下面的SQL 注入预防部分。

以下查询返回 User 表中每条记录的所有字段

// import the generated `User` type from the `@prisma/client` module
import { User } from "@prisma/client";

const result = await prisma.$queryRawUnsafe("SELECT * FROM User");

您还可以运行参数化查询。以下示例返回电子邮件包含字符串 [email protected] 的所有用户

prisma.$queryRawUnsafe("SELECT * FROM users WHERE email = $1", "[email protected]");

注意:Prisma 将 JavaScript 整数作为 INT8 发送到 PostgreSQL。这可能会与您只接受 INT4 作为输入的用户自定义函数冲突。如果您将参数化的 $queryRawUnsafe 查询与 PostgreSQL 数据库结合使用,请将输入类型更新为 INT8,或将查询参数强制转换为 INT4

有关使用参数化查询的更多详细信息,请参阅下面的参数化查询部分。

签名

$queryRawUnsafe<T = unknown>(query: string, ...values: any[]): PrismaPromise<T>;

$executeRaw

$executeRaw 返回受数据库操作影响的行数,例如 UPDATEDELETE。此函数返回数据库记录。以下查询更新数据库中的记录,并返回已更新记录数的计数

const result: number =
await prisma.$executeRaw`UPDATE User SET active = true WHERE emailValidated = true`;

该方法实现为标记模板,它允许您传递模板字面量,您可以在其中轻松插入您的变量。反过来,Prisma Client 会创建预处理语句,这些语句可以防止 SQL 注入

const emailValidated = true;
const active = true;

const result: number =
await prisma.$executeRaw`UPDATE User SET active = ${active} WHERE emailValidated = ${emailValidated};`;
警告

如果您使用字符串构建将不受信任的输入合并到传递给此方法的查询中,那么您就打开了 SQL 注入攻击的可能性。SQL 注入攻击可能会使您的数据暴露于修改或删除的风险。首选机制是在您运行此方法时包含查询的文本。有关此风险以及如何预防它的示例的更多信息,请参阅下面的SQL 注入预防部分。

注意事项

请注意

  • $executeRaw 不支持在单个字符串中包含多个查询(例如,ALTER TABLECREATE TABLE 一起)。

  • Prisma Client 提交预处理语句,而预处理语句只允许 SQL 语句的子集。例如,不允许使用 START TRANSACTION。您可以在此处了解更多关于 MySQL 在预处理语句中允许的语法

  • PREPARE 不支持 ALTER - 请参阅解决方法

  • 模板变量不能在 SQL 字符串字面量内部使用。例如,以下查询将不起作用

    const name = "Bob";
    await prisma.$executeRaw`UPDATE user SET greeting = 'My name is ${name}';`;

    相反,您可以将整个字符串作为变量传递,或者使用字符串连接

    const name = "My name is Bob";
    await prisma.$executeRaw`UPDATE user SET greeting = ${name};`;
    const name = "Bob";
    await prisma.$executeRaw`UPDATE user SET greeting = 'My name is ' || ${name};`;
  • 模板变量只能用于数据值(例如上面示例中的 email)。变量不能用于标识符,例如列名、表名或数据库名,或用于 SQL 关键字。例如,以下两个查询将不起作用

    const myTable = "user";
    await prisma.$executeRaw`UPDATE ${myTable} SET active = true;`;
    const ordering = "desc";
    await prisma.$executeRaw`UPDATE User SET active = true ORDER BY ${desc};`;

返回类型

$executeRaw 返回一个 number

签名

$executeRaw<T = unknown>(query: TemplateStringsArray | Prisma.Sql, ...values: any[]): PrismaPromise<number>;

$executeRawUnsafe()

$executeRawUnsafe() 方法允许您将原始字符串(或模板字符串)传递到数据库。与 $executeRaw 类似,它返回数据库记录,而是返回受影响的行数。

警告

如果您将此方法与用户输入一起使用(换句话说,SELECT * FROM table WHERE columnx = ${userInput}),那么您就打开了 SQL 注入攻击的可能性。SQL 注入攻击可能会使您的数据暴露于修改或删除的风险。

在任何可能的情况下,您都应该使用 $executeRaw 方法。当正确使用时,$executeRaw 方法会更安全,但请注意,在某些情况下,$executeRaw 方法也可能变得易受攻击。有关更多信息,请参阅下面的SQL 注入预防部分。

以下示例使用模板字符串更新数据库中的记录。然后,它返回已更新记录数的计数

const emailValidated = true;
const active = true;

const result = await prisma.$executeRawUnsafe(
`UPDATE User SET active = ${active} WHERE emailValidated = ${emailValidated}`
);

同样可以使用参数化查询编写

const result = prisma.$executeRawUnsafe(
"UPDATE User SET active = $1 WHERE emailValidated = $2",
"[email protected]",
true
);

有关使用参数化查询的更多详细信息,请参阅下面的参数化查询部分。

签名

$executeRawUnsafe<T = unknown>(query: string, ...values: any[]): PrismaPromise<number>;

原始查询类型映射

Prisma 将 $queryRaw$queryRawUnsafe 返回的任何数据库值映射到它们对应的JavaScript 类型。此行为与常规 Prisma 查询方法(如 findMany())相同。

信息

功能可用性

  • 在 v3.14.x 和 v3.15.x 版本中,原始查询类型映射通过预览功能 improvedQueryRaw 提供。我们在 4.0.0 版本中将原始查询类型映射设为正式发布 (GA),因此您无需在 4.0.0 或更高版本中使用 improvedQueryRaw
  • 在 4.0.0 版本之前,SQLite 不支持原始查询类型映射。

例如,以下是一个原始查询,它从表中选择具有 BigIntBytesDecimalDate 类型的列

const result = await prisma.$queryRaw`SELECT bigint, bytes, decimal, date FROM "Table";`;

console.log(result);
显示CLI结果
{ bigint: BigInt("123"), bytes: <Buffer 01 02>), decimal: Decimal("12.34"), date: Date("<some_date>") }

result 对象中,数据库值已映射到对应的 JavaScript 类型。

下表显示了数据库中使用的类型与原始查询返回的 JavaScript 类型之间的转换

数据库类型JavaScript 类型
文本字符串
32 位整数数字
32 位无符号整数BigInt
浮点数数字
双精度数数字
64 位整数BigInt
Decimal / 数值Decimal
BytesUint8Arrayv6 之前Buffer
Json对象
DateTime日期
日期日期
时间日期
Uuid字符串
Xml字符串

请注意,每种数据库类型的确切名称在不同数据库之间会有所不同 – 例如,布尔类型在 PostgreSQL 中称为 boolean,在 CockroachDB 中称为 STRING。有关每种数据库的类型名称的完整详细信息,请参阅标量类型参考

原始查询类型转换行为

使用 Prisma Client 的原始查询可能需要参数为 SQL 函数或查询的预期类型。Prisma Client 不进行细微的隐式转换。

例如,以下是使用 PostgreSQL 的 LENGTH 函数的查询,该函数仅接受 text 类型作为输入

await prisma.$queryRaw`SELECT LENGTH(${42});`;

此查询返回错误

// ERROR: function length(integer) does not exist
// HINT: No function matches the given name and argument types. You might need to add explicit type casts.

在这种情况下,解决方案是将 42 显式转换为 text 类型

await prisma.$queryRaw`SELECT LENGTH(${42}::text);`;
信息

功能可用性: 自 4.0.0 版本以来,此功能已正式发布 (GA)。在 v3.14.x 和 v3.15.x 版本中,它通过预览功能 improvedQueryRaw 提供。

对于 4.0.0 版本之前的上述示例,Prisma ORM 会静默地将 42 强制转换为 text,而不需要显式转换。

另一方面,以下原始查询现在可以正常工作,返回整数结果,并且以前失败

await prisma.$queryRaw`SELECT ${1.5}::int as int`;

// Now: [{ int: 2 }]
// Before: db error: ERROR: incorrect binary data format in bind parameter 1

事务

在 2.10.0 及更高版本中,您可以在事务内部使用 .$executeRaw().$queryRaw()

使用变量

$executeRaw$queryRaw 实现为标记模板。标记模板是在 Prisma Client 中将变量与原始 SQL 一起使用的推荐方法。

以下示例包含一个名为 ${userId} 的占位符

const userId = 42;
const result = await prisma.$queryRaw`SELECT * FROM User WHERE id = ${userId};`;

✔ 使用 $queryRaw$executeRaw 的标记模板版本的好处包括

  • Prisma Client 转义所有变量。
  • 标记模板与数据库无关 - 您无需记住变量应该写成 $1 (PostgreSQL) 还是 ? (MySQL)。
  • SQL Template Tag 使您可以访问有用的辅助函数
  • 嵌入式的命名变量更易于阅读。

注意:您不能将表名或列名传递到标记模板占位符中。例如,您不能 SELECT ? 并根据某些条件传入 *id, name

标记模板辅助函数

Prisma Client 专门使用 SQL Template Tag,它公开了许多辅助函数。例如,以下查询使用 join() 传入 ID 列表

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

const ids = [1, 3, 5, 10, 20];
const result = await prisma.$queryRaw`SELECT * FROM User WHERE id IN (${Prisma.join(ids)})`;

以下示例使用 emptysql 辅助函数来根据 userName 是否为空来更改查询

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

const userName = "";
const result = await prisma.$queryRaw`SELECT * FROM User ${
userName ? Prisma.sql`WHERE name = ${userName}` : Prisma.empty // Cannot use "" or NULL here!
}`;

ALTER 限制 (PostgreSQL)

PostgreSQL 不支持在预处理语句中使用 ALTER,这意味着以下查询将不起作用

await prisma.$executeRaw`ALTER USER prisma WITH PASSWORD "${password}"`;
await prisma.$executeRaw(Prisma.sql`ALTER USER prisma WITH PASSWORD "${password}"`);

您可以使用以下查询,但请注意,这可能是不安全的,因为 ${password} 未转义

await prisma.$executeRawUnsafe('ALTER USER prisma WITH PASSWORD "$1"', password})

不支持的类型

Unsupported 类型需要在 $queryRaw$queryRawUnsafe 中使用之前转换为 Prisma Client 支持的类型。例如,以下模型具有一个 location 字段,其类型为 Unsupported

model Country {
location Unsupported("point")?
}

以下对不支持字段的查询将不起作用

await prisma.$queryRaw`SELECT location FROM Country;`;

相反,将 Unsupported 字段转换为任何受支持的 Prisma Client 类型,如果您的 Unsupported 列支持转换

您可能希望将 Unsupported 列转换为的最常见类型是 String。例如,在 PostgreSQL 上,这将映射到 text 类型

await prisma.$queryRaw`SELECT location::text FROM Country;`;

因此,数据库将提供您的数据的 String 表示形式,Prisma Client 支持该形式。

有关受支持的 Prisma 类型的详细信息,请参阅相关数据库的Prisma 连接器概述

SQL 注入预防

在 Prisma Client 中避免 SQL 注入的理想方法是尽可能使用 ORM 模型来执行查询。

在不可能使用 ORM 模型并且需要原始查询的情况下,Prisma Client 提供了各种原始方法,但重要的是要安全地使用这些方法。

本节将提供各种安全和不安全地使用这些方法的示例。您可以在Prisma Playground 中测试这些示例。

$queryRaw$executeRaw

$queryRaw$executeRaw 的简单、安全使用

当您使用标记模板并将所有查询作为预处理语句发送时,这些方法可以通过转义所有变量来降低 SQL 注入的风险。

$queryRaw`...`; // Tagged template
$executeRaw`...`; // Tagged template

以下示例是安全的 ✅,免受 SQL 注入

const inputString = `'Sarah' UNION SELECT id, title FROM "Post"`;
const result = await prisma.$queryRaw`SELECT id, name FROM "User" WHERE name = ${inputString}`;

console.log(result);

$queryRaw$executeRaw 的不安全使用

但是,也可能以不安全的方式使用这些方法。

一种方法是人为地生成一个不安全地连接用户输入的标记模板。

以下示例容易受到 ❌ SQL 注入攻击

// Unsafely generate query text
const inputString = `'Sarah' UNION SELECT id, title FROM "Post"`; // SQL Injection
const query = `SELECT id, name FROM "User" WHERE name = ${inputString}`;

// Version for Typescript
const stringsArray: any = [...[query]];

// Version for Javascript
const stringsArray = [...[query]];

// Use the `raw` property to impersonate a tagged template
stringsArray.raw = [query];

// Use queryRaw
const result = await prisma.$queryRaw(stringsArray);
console.log(result);

使这些方法容易受到攻击的另一种方法是误用 Prisma.raw 函数。

以下示例都容易受到 ❌ SQL 注入攻击

const inputString = `'Sarah' UNION SELECT id, title FROM "Post"`;
const result = await prisma.$queryRaw`SELECT id, name FROM "User" WHERE name = ${Prisma.raw(
inputString
)}`;
console.log(result);
const inputString = `'Sarah' UNION SELECT id, title FROM "Post"`;
const result = await prisma.$queryRaw(
Prisma.raw(`SELECT id, name FROM "User" WHERE name = ${inputString}`)
);
console.log(result);
const inputString = `'Sarah' UNION SELECT id, title FROM "Post"`;
const query = Prisma.raw(`SELECT id, name FROM "User" WHERE name = ${inputString}`);
const result = await prisma.$queryRaw(query);
console.log(result);

在更复杂的场景中安全地使用 $queryRaw$executeRaw

构建与查询执行分离的原始查询

如果您想在其他地方或与参数分开构建原始查询,您需要使用以下方法之一。

在此示例中,sql 辅助方法用于通过安全地包含变量来构建查询文本。它是安全的 ✅,免受 SQL 注入

// inputString can be untrusted input
const inputString = `'Sarah' UNION SELECT id, title FROM "Post"`;

// Safe if the text query below is completely trusted content
const query = Prisma.sql`SELECT id, name FROM "User" WHERE name = ${inputString}`;

const result = await prisma.$queryRaw(query);
console.log(result);

在这个安全的 ✅,免受 SQL 注入的示例中,sql 辅助方法用于构建查询文本,包括输入值的参数标记。每个变量都由一个标记符号表示(MySQL 为 ?,PostgreSQL 为 $1$2 等)。请注意,这些示例仅显示 PostgreSQL 查询。

// Version for Typescript
const query: any;

// Version for Javascript
const query;

// Safe if the text query below is completely trusted content
query = Prisma.sql`SELECT id, name FROM "User" WHERE name = $1`;

// inputString can be untrusted input
const inputString = `'Sarah' UNION SELECT id, title FROM "Post"`;
query.values = [inputString];

const result = await prisma.$queryRaw(query);
console.log(result);

注意:PostgreSQL 变量用 $1 等表示

在其他地方或分阶段构建原始查询

如果您想在查询执行位置以外的其他位置构建原始查询,理想的方法是从查询的片段创建一个 Sql 对象,并将参数值传递给它。

在以下示例中,我们有两个变量要参数化。只要传递给 Prisma.sql 的查询字符串仅包含受信任的内容,该示例就是安全的 ✅,免受 SQL 注入

// Example is safe if the text query below is completely trusted content
const query1 = `SELECT id, name FROM "User" WHERE name = `; // The first parameter would be inserted after this string
const query2 = ` OR name = `; // The second parameter would be inserted after this string

const inputString1 = "Fred";
const inputString2 = `'Sarah' UNION SELECT id, title FROM "Post"`;

const query = Prisma.sql([query1, query2, ""], inputString1, inputString2);
const result = await prisma.$queryRaw(query);
console.log(result);

注意:请注意,作为第一个参数传递的字符串数组 Prisma.sql 需要在末尾有一个空字符串,因为 sql 函数期望的查询片段比参数数量多一个。

如果您想将原始查询构建成一个大型字符串,这仍然是可能的,但这需要谨慎,因为它使用了可能危险的 Prisma.raw 方法。您还需要使用适用于您数据库的正确参数标记来构建查询,因为 Prisma 将无法像通常那样为相关数据库提供标记。

以下示例是安全的 ✅,免受 SQL 注入攻击,只要传递给 Prisma.raw 的查询字符串仅包含受信任的内容

// Version for Typescript
const query: any;

// Version for Javascript
const query;

// Example is safe if the text query below is completely trusted content
const query1 = `SELECT id, name FROM "User" `;
const query2 = `WHERE name = $1 `;

query = Prisma.raw(`${query1}${query2}`);

// inputString can be untrusted input
const inputString = `'Sarah' UNION SELECT id, title FROM "Post"`;
query.values = [inputString];

const result = await prisma.$queryRaw(query);
console.log(result);

$queryRawUnsafe$executeRawUnsafe

不安全地使用 $queryRawUnsafe$executeRawUnsafe

如果您不能使用标签模板,您可以改用 $queryRawUnsafe$executeRawUnsafe。但是,请注意,这些函数会显著增加代码中 SQL 注入漏洞的风险

以下示例连接了 queryinputString。Prisma Client ❌ 无法在此示例中转义 inputString,这使其容易受到 SQL 注入的攻击

const inputString = '"Sarah" UNION SELECT id, title, content FROM Post'; // SQL Injection
const query = "SELECT id, name, email FROM User WHERE name = " + inputString;
const result = await prisma.$queryRawUnsafe(query);

console.log(result);

参数化查询

作为标签模板的替代方案,$queryRawUnsafe 支持标准参数化查询,其中每个变量都由一个符号表示(MySQL 为 ?,PostgreSQL 为 $1$2 等)。请注意,示例仅显示了 PostgreSQL 查询。

以下示例是安全的 ✅,免受 SQL 注入

const userName = "Sarah";
const email = "[email protected]";
const result = await prisma.$queryRawUnsafe(
"SELECT * FROM User WHERE (name = $1 OR email = $2)",
userName,
email
);

注意:PostgreSQL 变量由 $1$2 表示

与标签模板一样,当变量以这种方式提供时,Prisma Client 会转义所有变量。

注意:您不能将表名或列名作为变量传递到参数化查询中。例如,您不能 SELECT ? 并根据某些条件传入 *id, name

参数化 PostgreSQL ILIKE 查询

当您使用 ILIKE 时,% 通配符应包含在变量本身中,而不是查询(string)中。此示例是安全的 ✅,免受 SQL 注入攻击。

const userName = "Sarah";
const emailFragment = "prisma.io";
const result = await prisma.$queryRawUnsafe(
'SELECT * FROM "User" WHERE (name = $1 OR email ILIKE $2)',
userName,
`%${emailFragment}`
);

注意:使用 %$2 作为参数将不起作用

使用 MongoDB 的原始查询

对于 3.9.0 及更高版本的 MongoDB,Prisma Client 公开了三种允许您发送原始查询的方法。您可以使用

  • $runCommandRaw 来对数据库运行命令
  • <model>.findRaw 来查找零个或多个与过滤器匹配的文档。
  • <model>.aggregateRaw 对集合执行聚合操作。

$runCommandRaw()

$runCommandRaw() 对数据库运行原始 MongoDB 命令。作为输入,它接受所有 MongoDB 数据库命令,但以下情况除外

当您使用 $runCommandRaw() 运行 MongoDB 数据库命令时,请注意以下事项

  • 当您调用 $runCommandRaw() 时传递的对象必须遵循 MongoDB 数据库命令的语法。
  • 您必须使用适用于 MongoDB 数据库命令的适当角色连接到数据库。

在以下示例中,一个查询插入了两个具有相同 _id 的记录。这绕过了正常的文档验证。

prisma.$runCommandRaw({
insert: "Pets",
bypassDocumentValidation: true,
documents: [
{
_id: 1,
name: "Felinecitas",
type: "Cat",
breed: "Russian Blue",
age: 12,
},
{
_id: 1,
name: "Nao Nao",
type: "Dog",
breed: "Chow Chow",
age: 2,
},
],
});
警告

不要将 $runCommandRaw() 用于包含 "find""aggregate" 命令的查询,因为您可能无法获取所有数据。这是因为 MongoDB 返回一个 游标,该游标附加到您的 MongoDB 会话,并且您可能每次都无法访问相同的 MongoDB 会话。对于这些查询,您应该改用专门的 findRaw()aggregateRaw() 方法。

返回类型

$runCommandRaw() 返回一个 JSON 对象,其形状取决于输入。

签名

$runCommandRaw(command: InputJsonObject): PrismaPromise<JsonObject>;

findRaw()

<model>.findRaw() 返回实际的数据库记录。它将查找零个或多个与 User 集合上的过滤器匹配的文档

const result = await prisma.user.findRaw({
filter: { age: { $gt: 25 } },
options: { projection: { _id: false } },
});

返回类型

<model>.findRaw() 返回一个 JSON 对象,其形状取决于输入。

签名

<model>.findRaw(args?: {filter?: InputJsonObject, options?: InputJsonObject}): PrismaPromise<JsonObject>;
  • filter:查询谓词过滤器。如果未指定,则集合中的所有文档都将匹配谓词
  • options:传递给 find 命令 的其他选项。

aggregateRaw()

<model>.aggregateRaw() 返回聚合的数据库记录。它将在 User 集合上执行聚合操作

const result = await prisma.user.aggregateRaw({
pipeline: [
{ $match: { status: "registered" } },
{ $group: { _id: "$country", total: { $sum: 1 } } },
],
});

返回类型

<model>.aggregateRaw() 返回一个 JSON 对象,其形状取决于输入。

签名

<model>.aggregateRaw(args?: {pipeline?: InputJsonObject[], options?: InputJsonObject}): PrismaPromise<JsonObject>;
  • pipeline:用于通过 聚合管道 处理和转换文档流的聚合阶段数组。
  • options:传递给 aggregate 命令 的其他选项。

注意事项

当使用自定义对象(如 ObjectIdDate)时,您将必须根据 MongoDB 扩展 JSON 规范 传递它们。 例子

const result = await prisma.user.aggregateRaw({
pipeline: [
{ $match: { _id: { $oid: id } } }
// ^ notice the $oid convention here
],
});