跳到主要內容

原始查詢

警告

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 = "emelie@prisma.io";
const result = await prisma.$queryRaw`SELECT * FROM User WHERE email = ${email}`;

你也可以使用 Prisma.sql 助手函式,事實上,$queryRaw 方法只接受模板字串或 Prisma.sql 助手函式

const email = "emelie@prisma.io";
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: "emelie@prisma.io", name: "Emelie" },
{ id: 2, email: "yin@prisma.io", 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");

你還可以執行引數化查詢。以下示例返回所有電子郵件包含字串 emelie@prisma.io 的使用者

prisma.$queryRawUnsafe("SELECT * FROM users WHERE email = $1", "emelie@prisma.io");

注意: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",
"yin@prisma.io",
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
位元組Uint8Array (v6 之前: Buffer)
Json物件
日期時間日期
日期日期
時間日期
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 模板標籤 讓你能夠使用有用的助手函式
  • 嵌入式命名變數更易讀。

注意:你不能將表名或列名傳遞到標籤模板佔位符中。例如,你不能根據某些條件 SELECT ? 並傳入 *id, name

標籤模板助手函式

Prisma Client 特別使用了 SQL 模板標籤,它暴露了許多助手函式。例如,以下查詢使用 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 支援的型別。例如,以下模型有一個 Unsupported 型別的 location 欄位

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 模型執行查詢。

如果無法實現,並且需要原始查詢,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 通常無法為相關資料庫提供標記。

只要傳遞給 Prisma.raw 的查詢字串只包含受信任的內容,以下示例對 SQL 注入就是安全的 ✅

// 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 = "sarah@prisma.io";
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
],
});

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