跳到主要內容

分頁

Prisma Client 支援偏移分頁和基於遊標的分頁。

偏移分頁

偏移分頁使用 skiptake 來跳過一定數量的結果並選擇一個有限的範圍。以下查詢跳過前3條 Post 記錄並返回第4至第7條記錄

const results = await prisma.post.findMany({
skip: 3,
take: 4,
})

要實現結果分頁,只需 skip 頁面數乘以每頁顯示的結果數。

✔ 偏移分頁的優點

  • 您可以立即跳轉到任何頁面。例如,您可以 skip 200條記錄並 take 10條,這模擬了直接跳轉到結果集的第21頁(底層SQL使用 OFFSET)。這在基於遊標的分頁中是不可能實現的。
  • 您可以以任何排序順序對相同的結果集進行分頁。例如,您可以跳轉到按名字排序的 User 記錄列表的第21頁。這在基於遊標的分頁中是不可能實現的,因為它要求按唯一、順序的列進行排序。

✘ 偏移分頁的缺點

  • 偏移分頁在資料庫層面**無法擴充套件**。例如,如果您跳過200,000條記錄並取出前10條,資料庫仍然需要遍歷前200,000條記錄才能返回您請求的10條——這會負面影響效能。

偏移分頁的用例

  • 對小型結果集進行淺層分頁。例如,一個允許您按作者過濾 Post 記錄並對結果進行分頁的部落格介面。

示例:過濾和偏移分頁

以下查詢返回 email 欄位包含 prisma.io 的所有記錄。該查詢跳過前40條記錄並返回第41至第50條記錄。

const results = await prisma.post.findMany({
skip: 40,
take: 10,
where: {
email: {
contains: 'prisma.io',
},
},
})

示例:排序和偏移分頁

以下查詢返回 email 欄位包含 Prisma 的所有記錄,並按 title 欄位排序結果。該查詢跳過前200條記錄並返回第201至第220條記錄。

const results = await prisma.post.findMany({
skip: 200,
take: 20,
where: {
email: {
contains: 'Prisma',
},
},
orderBy: {
title: 'desc',
},
})

基於遊標的分頁

基於遊標的分頁使用 cursortake 來返回給定**遊標**之前或之後有限數量的結果。遊標會在結果集中標記您的位置,並且必須是一個唯一、順序的列——例如 ID 或時間戳。

以下示例返回前4條包含單詞 "Prisma"Post 記錄,並將最後一條記錄的 ID 儲存為 myCursor

**注意**:由於這是第一次查詢,沒有遊標可傳入。

const firstQueryResults = await prisma.post.findMany({
take: 4,
where: {
title: {
contains: 'Prisma' /* Optional filter */,
},
},
orderBy: {
id: 'asc',
},
})

// Bookmark your location in the result set - in this
// case, the ID of the last post in the list of 4.

const lastPostInResults = firstQueryResults[3] // Remember: zero-based index! :)
const myCursor = lastPostInResults.id // Example: 29

下圖顯示了前4個結果的 ID——即第1頁。下一次查詢的遊標是 **29**

第二次查詢返回包含單詞 "Prisma" 並在**提供的遊標之後**的前4條 Post 記錄(換句話說——ID 大於 **29** 的記錄)

const secondQueryResults = await prisma.post.findMany({
take: 4,
skip: 1, // Skip the cursor
cursor: {
id: myCursor,
},
where: {
title: {
contains: 'Prisma' /* Optional filter */,
},
},
orderBy: {
id: 'asc',
},
})

const lastPostInResults = secondQueryResults[3] // Remember: zero-based index! :)
const myCursor = lastPostInResults.id // Example: 52

下圖顯示了 ID 為 **29** 的記錄**之後**的前4條 Post 記錄。在此示例中,新遊標是 **52**

常見問題

我總是需要 skip: 1 嗎?

如果您不 skip: 1,您的結果集將包含您之前的遊標。第一次查詢返回四個結果,遊標是 **29**

不使用 skip: 1,第二次查詢返回遊標之後(並*包含*)的4個結果

如果您 skip: 1,則不包含遊標

您可以根據所需的分頁行為選擇是否使用 skip: 1

我可以猜測遊標的值嗎?

如果您猜測下一個遊標的值,您將在結果集中分頁到未知位置。儘管 ID 是順序的,但您無法預測增量速率(22032123 更常見,尤其是在過濾後的結果集中)。

基於遊標的分頁是否使用底層資料庫中游標的概念?

不,遊標分頁不使用底層資料庫中的遊標(例如 PostgreSQL)。

如果遊標值不存在會發生什麼?

使用不存在的遊標會返回 null。Prisma Client 不會嘗試定位相鄰值。

✔ 基於遊標的分頁的優點

  • 基於遊標的分頁**可擴充套件**。底層 SQL 不使用 OFFSET,而是查詢所有 ID 大於 cursor 值的 Post 記錄。

✘ 基於遊標的分頁的缺點

  • 您必須按遊標進行排序,遊標必須是唯一、順序的列。
  • 您無法僅使用遊標跳轉到特定頁面。例如,如果不首先請求第1至第399頁,您無法準確預測哪個遊標代表第400頁(每頁20條)的開頭。

基於遊標的分頁的用例

  • 無限滾動——例如,按日期/時間降序排序部落格文章,並一次請求10篇部落格文章。
  • 分批遍歷整個結果集——例如,作為長時間執行的資料匯出的一部分。

示例:過濾和基於遊標的分頁

const secondQuery = await prisma.post.findMany({
take: 4,
cursor: {
id: myCursor,
},
where: {
title: {
contains: 'Prisma' /* Optional filter */,
},
},
orderBy: {
id: 'asc',
},
})

排序和基於遊標的分頁

基於遊標的分頁要求您按順序、唯一的列進行排序,例如 ID 或時間戳。此值(稱為遊標)會在結果集中標記您的位置,並允許您請求下一組資料。

示例:使用基於遊標的分頁向後翻頁

要向後翻頁,請將 take 設定為負值。以下查詢返回4條 Post 記錄,其 id 小於200,不包括遊標

const myOldCursor = 200

const firstQueryResults = await prisma.post.findMany({
take: -4,
skip: 1,
cursor: {
id: myOldCursor,
},
where: {
title: {
contains: 'Prisma' /* Optional filter */,
},
},
orderBy: {
id: 'asc',
},
})
© . This site is unofficial and not affiliated with Prisma Data, Inc.