มีสองกลยุทธ์: แบบ offset (limit/offset) และ แบบ cursor GraphQL ไม่มี pagination มาให้ในตัว แต่มาตรฐานของชุมชนคือ spec Relay Connection ซึ่งกำหนดรูปแบบของ cursor pagination อย่างเป็นทางการ
มีสองกลยุทธ์: แบบ offset (limit/offset) และ แบบ cursor GraphQL ไม่มี pagination มาให้ในตัว แต่มาตรฐานของชุมชนคือ spec Relay Connection ซึ่งกำหนดรูปแบบของ cursor pagination อย่างเป็นทางการ
items(limit: 10, offset: 20)) นั้นเรียบง่ายแต่พังกับข้อมูลที่เปลี่ยนแปลงสด ๆ: หากมีการ insert แถวใหม่ในขณะที่ผู้ใช้กำลังเลื่อนหน้า รายการจะเลื่อนตำแหน่งและคุณจะเห็นข้อมูลซ้ำหรือหายไป นอกจากนี้ยังช้าลงเมื่อ offset ลึก (DB ยังต้อง scan แถวที่ข้ามไป)connection จะห่อ list ไว้ใน edges (แต่ละตัวมี cursor และ node) พร้อมกับ pageInfo:
type Query {
posts(first: Int!, after: String): PostConnection! # first = page size, after = cursor
}
type PostConnection {
edges: [PostEdge!]!
pageInfo: PageInfo!
}
type PostEdge {
cursor: String! # opaque token for THIS node's position
node: Post! # the actual item
}
type PageInfo {
endCursor: String # feed this back as 'after' for the next page
hasNextPage: Boolean! # so the client knows when to stop
}
// resolver: fetch ONE extra row to compute hasNextPage cheaply
const rows = await db.posts.find({ after: args.after, limit: args.first + 1 });
const hasNextPage = rows.length > args.first;
const page = rows.slice(0, args.first);
return {
edges: page.map((p) => ({ node: p, cursor: encodeCursor(p.id) })),
pageInfo: { endCursor: page.at(-1) && encodeCursor(page.at(-1).id), hasNextPage },
};
cursor เป็นค่า opaque (ทึบ อ่านความหมายไม่ได้) — มักเป็น base64 ของ sort key — client จึงมองมันเป็น token ไม่ใช่ตัวเลข
การเลือกระหว่าง offset กับ cursor แสดงว่าคุณเข้าใจ ความสอดคล้อง (consistency) ภายใต้การเขียนพร้อมกัน และ ประสิทธิภาพของหน้าที่ลึก การรู้รูปทรงของ Relay connection สำคัญ เพราะ client อย่าง Apollo/Relay มีการจัดการ cache สำหรับมันมาให้ในตัว
คลังคำถามสัมภาษณ์งาน IT พร้อมคำตอบโดยละเอียด — ตั้งแต่ระดับ Junior ถึง Senior
บริจาค