Pagination: Cursor-Based
Sahifalash: Cursor asosida
Kitobni "45-sahifa"dan o'qishni davom ettirasiz deylik. Agar kimdir kitobning BOSHIDAGI 3 betni OLIB TASHLASA, sizning "45-sahifa"ngiz ENDI boshqa matnga to'g'ri keladi — siz nimanidir O'TKAZIB YUBORASIZ yoki QAYTA o'qiysiz. Lekin agar siz sahifa RAQAMI o'rniga, kitobga JISMONIY ZAKLADKA (bookmark) qo'ysangiz — "...gacha o'qidim" — bu muammo BO'LMAYDI: zakladka HAR DOIM to'g'ri joyni ko'rsatadi, hatto oldingi betlar o'zgarsa ham. Cursor-based pagination — aynan shu "zakladka" g'oyasi: sahifa RAQAMI (offset) o'rniga, OXIRGI ko'rilgan yozuvning O'ZI ishlatiladi.
package main
import (
"fmt"
"strconv"
)
type Book struct {
ID string
}
type Page struct {
Books []*Book
NextCursor string
}
// listAfter — books ID bo'yicha o'sib boruvchi tartibda saralangan deb faraz qilinadi
func listAfter(books []*Book, cursor string, limit int) Page {
start := 0
if cursor != "" {
cursorNum, _ := strconv.Atoi(cursor)
for i, b := range books {
idNum, _ := strconv.Atoi(b.ID)
if idNum > cursorNum {
start = i
break
}
start = i + 1
}
}
end := start + limit
if end > len(books) {
end = len(books)
}
page := books[start:end]
next := ""
if end < len(books) {
next = page[len(page)-1].ID
}
return Page{Books: page, NextCursor: next}
}
func printPage(p Page) {
var ids []string
for _, b := range p.Books {
ids = append(ids, b.ID)
}
fmt.Println(ids, "next:", p.NextCursor)
}
func main() {
books := []*Book{{"1"}, {"2"}, {"3"}, {"4"}, {"5"}}
page1 := listAfter(books, "", 2)
printPage(page1)
page2 := listAfter(books, page1.NextCursor, 2)
printPage(page2)
page3 := listAfter(books, page2.NextCursor, 2)
printPage(page3)
}cursor — oxirgi olingan yozuvning ID'si (bo'sh bo'lsa "boshidan" degani). listAfter HAR SAFAR "cursor'dan KATTA ID'lar"ni qidiradi — offset kabi "nechinchi ELEMENT"ni emas, BALKI "qaysi ELEMENTDAN keyin"ni so'raydi. NextCursor — agar YANA yozuv qolgan bo'lsa, KEYINGI so'rovda ishlatiladigan cursor'ni qaytaradi; bo'sh bo'lsa — bu OXIRGI sahifa degani.
Bu naqshning ustunligi shunda: agar sahifalar ORASIDA (masalan foydalanuvchi 1-sahifani o'qib bo'lguncha) BIROR yozuv O'CHIRILSA yoki qo'shilsa, offset asosidagi sahifalash CHALKASHIB ketadi (ba'zi yozuvlar IKKI MARTA ko'rinadi yoki UMUMAN ko'rinmaydi), cursor asosidagi sahifalash esa BUNDAY MUAMMODAN XOLI — chunki u "nechinchi o'rinda" emas, "QAYSI yozuvdan keyin" deb so'raydi.
>_ Exercise
Offset asosidagi sahifalashning O'CHIRISHDAGI MUAMMOSINI, cursor bilan SOLISHTIRIB ko'ring.
- •offsetPage(books []*Book, limit, offset int) []*Book funksiyasini yozing ('Pagination: Limit & Offset' darsidagi paginate bilan bir xil mantiq)
- •original ro'yxat ({"1"}..{"5"}) uchun offsetPage(original, 2, 0) ni chaqirib, natijani chop eting
- •"2" ID'li kitob O'CHIRILGAN deb faraz qiling (afterDelete — {"1"},{"3"},{"4"},{"5"}), va offsetPage(afterDelete, 2, 2) natijasini chop eting — "3" O'TKAZIB YUBORILGANINI ko'rasiz
- •listAfter bilan xuddi shu ikki holatni (original va afterDelete) taqqoslang — cursor '3'ni O'TKAZIB YUBORMASLIGINI ko'rsating
Stuck? Reveal a hint to help you.
Key Takeaway
Key Takeaway:
Cursor-based sahifalash — "nechinchi o'rin" (offset) emas, "QAYSI yozuvdan keyin" (cursor) so'raydi; shu sabab, sahifalar orasida ma'lumot o'chirilsa yoki qo'shilsa ham, natija BUZILMAYDI — bu katta, tez o'zgaruvchan ma'lumotlar uchun standart yechim.
NEXT UP
Filtering & Sorting Query Parameters
$ go run main.go
Kodingizni ishga tushiring