iT邦幫忙

2024 iThome 鐵人賽

DAY 19
0

不管在任何地方,要實踐 Pagination 功能最基本都要有兩個功能:

  • 分頁
  • 總頁面數

只要有了這兩個資訊就可以實做出一個基本的內容分頁功能了。

總頁面數倒是不難,可以簡單的用 count 方法完成:

count(*[_type == "blogPost"])

至於分頁功能,則是可以使用 [0...10] 的查詢語法去完成,假設每 5 篇文章一頁,現在是在第 5 頁,便可以使用:

*[_type == "blogPost"][25...30]

若是要以日期排序的話則使用 order() 方法來做:
( 建議都還是要指定排序欄位的,不然天知道用什麼排序的 )

*[_type == "blogPost"] | order(publishedAt)[25...30]

排序的效能問題

不過,在官方的文件上有提到使用這種方法做分頁的查詢是非常沒有效率的,因為 Sanity 底層運行的邏輯是先查詢出來所有的結果,並且對他們進行排序後再取得指定的範圍。

以剛才的排序來說:

*[_type == "blogPost"] | order(publishedAt)[25...30]

這段便是以

*[_type == "blogPost"]

取得所有的文章內容後,再以 order() 方法排序:

order(publishedAt)

排序完成的最後才是取得選取的範圍

[25...30]

經過這一系列的動作後才得到結果。
其實在資料量不多的時候並不會有什麼效能的問題,只是當資料筆數有個十來萬的時候就會稍微要有點問題了。
想像一下我的文章如果有幾萬篇,像這種查詢語法就勢必會帶來查詢上的負擔了:

*[_type == "blogPost"] | order(publishedAt)[10000..10005]

對於效能的解決方案, Sanity 官方給出了一個解決方法,以我們的查詢來說,在查詢的時候就給出條件限制,像這樣:

*[_type == "blogPost" && publishedAt > $lastPublishedAt] | order(publishedAt)[0...5]

不要再指定最後面的查詢數字,查詢的數字保持在 0...5,取而代之的是在查詢的時候就把日期最後日期限制進去。
這麼一來在查詢速度上就會有很大的改進了。

可是這樣還不是全部,單純只用 publishedAt > $lastPublishedAt 的話,要是有同一天發布的文章可能就會不小心被過濾掉了。

所以為了要避免這錯誤,可以多加入一個唯一的欄位來做查詢,進而保證每筆資料都會被查詢出來。
官方建議是加入 _id 作為唯一識別來確保唯一性,像是這樣:

*[
  _type == "blogPost"
  && (
	  publishedAt > $lastPublishedAt
	  || (publishedAt > $lastPublishedAt && _id != $lastId)
  )
] | order(publishedAt)[0...5]

不過我個人覺得用 title,作為另一個識別應該也是可以的,所以我選用 title。

*[
  _type == "blogPost"
  && (
	  publishedAt > $lastPublishedAt
	  || (publishedAt > $lastPublishedAt && title != $title)
  )
] | order(publishedAt)[0...5]

接著就可以去修改 Next.js 前端專案的查詢語法了:

import { defineQuery } from "next-sanity";

export const BLOG_POSTS_QUERY = defineQuery(`*[
  _type == "blogPost"
  && (publishedAt > $lastPublishedAt
  || (publishedAt > $lastPublishedAt && title > $title))
] | order(publishedAt)[0...5]
`);

設定完之後記得回到 Sanity 專案內執行 typegen 指令重新產生型別檔:

sanity typegen generate

其實必須說,這兩種方法各有各的使用場景,並不是說第一種搜尋法可能會比較慢就完全不能用。

https://ithelp.ithome.com.tw/upload/images/20241005/20101989j4X3KS9dou.jpg

粗略的分,有這三種載入模式可以選擇。

以本篇提到的第一種主要以頁數控制的分頁法來說 ( [5...10] )
比較適合分頁式的切換模式,網址會跟著頁面變更來改變:

而本篇提到的第二種查詢方法,使用 filter 進行條件判斷的可以換來更快的速度,則比較適合的是Load More無限滾動 模式,網址是不會跟著頁面進行改動的,頁面也不會因為載入更多資料而改變頁面的網址。

這種的搜尋結構比較適合像是 Medium 那種無限往下滾動的,不會因內容改變 url 結構的設計。


上一篇
Day 18 - 首頁樣式調整
下一篇
Day 20 - 建立網站設定資料型別
系列文
用 Sanity 跟 Nextjs 重寫個人部落格30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言