-
Notifications
You must be signed in to change notification settings - Fork 0
Project 11 Create Pagination Search
ในส่วนนี้จะเป็นส่วนของการสร้าง Pagination และ Search ตั้งแต่ที่ Database เนื่องจากเมื่่อข้อมูลมีมากขึ้น การที่เราจะดึงข้อมูลมาทั้งหมดมาแสดงที่หน้าเว็บจะทำให้หน้าเว็บช้าลง และการที่เราจะทำการค้นหาข้อมูลจากข้อมูลทั้งหมดก็จะทำให้หน้าเว็บช้าลงด้วย ดังนั้นเราจะทำการสร้าง Pagination และ Search ที่ Database ก่อน
เราจะเริ่มจากการสร้าง Pagination ง่ายๆ ก่อน โดยเราจะใช้ที่ Query ข้อมูลจาก Database โดยใช้ limit และ skip ในการ Query ข้อมูล โดย limit จะบอกว่าเราจะดึงข้อมูลกี่ตัว และ skip จะบอกว่าเราจะข้ามข้อมูลกี่ตัว ดังนั้นเราจะสร้าง API ที่จะ Query ข้อมูลจาก Database โดยใช้ limit และ skip ดังนี้
-
เข้าไปในไฟล์
product.routes.jsใน routes -
ใน route get ของ Product สร้างตัวแปร
pageและsizeออกมา โดย size คือจำนวนข้อมูลที่จะดึงต่อหน้า และ page คือหน้าที่เราจะดึงข้อมูล -
สร้าง
skipโดยskipคือจำนวนข้อมูลที่เราจะข้ามไป เพราะว่าในคำสั่ง find ของ mongoose เราไม่สามารถใส่ size ลงไปตรง ๆ ได้ ดังนั้นเราจะต้องใช้skipในการข้ามข้อมูลไป โดยเรากำหนดให้skip = (page - 1) * size -
ใช้
sizeและskipในการ Query ข้อมูลจาก Database ดังนี้
router.get('/', async (req, res) => {
const page = 1
const size = 5
const skip = (page - 1) * size
const result = await Product.find().limit(size).skip(skip)
res.json({ rows: result })
})-
ลองดูผลลัพธ์ที่ Postman หรือ Browser ดูว่าข้อมูลที่ได้มาถูกต้องหรือไม่ (ถ้าจำนวน product มีมากกว่า 5 ตัวจะเห็นผล แต่ถ้าน้อยกว่านั้น จะไม่เห็นผล)
-
จะสังเกตุว่าข้อมูลจะเรียงลำดับจากที่เข้าไปก่อน และถ้าเราเข้าไปเพิ่มข้อมูลใหม่ ข้อมูลใหม่จะอยู่หลังข้อมูลเดิม ดังนั้นเราจะเรียงข้อมูลจากใหม่สุดก่อน โดยเราจะใช้
sortในการเรียงข้อมูล ดังนี้
router.get('/', async (req, res) => {
const page = 1
const size = 5
const skip = (page - 1) * size
const result = await Product.find().sort({ _id: -1 }).limit(size).skip(skip)
res.json({ rows: result })
})อย่างไรก็ได้ การ Fix size สำหรับการทำ Pagination อาจไม่เหมาะสมเท่าไหร่นัก เพราะว่าบางที บางหน้าใน frontend เราอาจจะต้องการข้อมูลมาก บางหน้าอาจจะต้องการข้อมูลน้อย ดังนั้น เราจะให้ User ที่ใช้ API สามารถกำหนด limit และ page ได้ด้วย
- รับค่า
pageและsizeจาก Query String ด้วยreq.queryและให้ default ให้page = 1และsize = 5ดังนี้
const page = req?.query?.page || 1
const size = req?.query?.size || 5-
ใช้
pageและsizeในการ Query ข้อมูลจาก Database โดยเราใส่ในโปรแกรม Postman ที่ Query Params ใส่ keypageและsizeแล้วใส่ค่าตามต้องการลงไป จะพบว่า URL ข้างบนของเราจะเปลี่ยนไปโดยมี?page=1&size=5ตามหลัง URL ของเรา สิ่งนี้แหละเราเรียกว่า Query String -
ลองดูผลลัพธ์ที่ Postman ดูว่าข้อมูลที่ได้มาถูกต้องหรือไม่ แล้วลองดูว่าเมื่อเปลี่ยน page หรือ size แล้ว ข้อมูลเปลี่ยนแปลงหรือไม่

สมมติว่าเดิม เรามีหน้า Product List ของเราที่มีหน้าตาคล้ายๆ ประมาณนี้

หรือตามโค้ดตัวอย่าง ตัวอย่างโค้ด
เราจะเห็นว่ามันจะออกมาแค่ 5 ชิ้น เพราะเราตั้ง Pagination Size ค่า Default ไว้ที่ 5 และ ไม่ได้มีการส่งค่าอื่นไปที่ API ในตรงนี้ เราจะให้ Frontend ส่ง Query ไปว่า เราจะใช้จำนวน Size เท่าไหร่
- ในหน้า ProductList เพิ่ม State สำหรับ Size ดังนี้
const [size, setSize] = useState(5)- ส่วนที่เรา Get Product เราใส่ Query เพิ่ม
sizeของเราลงไป โดยใช้เครื่องหมาย ? ตามด้วย key ของเราคือsizeแล้วตามด้วย value คือ size ใน state
const getAllProducts = () => {
axios
.get(`${process.env.REACT_APP_API_URL}/product?size=${size}`)
.then((res) => {
setProducts(res?.data?.rows)
console.log('Products ', res?.data?.rows)
})
.catch((error) => {
console.error('Error', error?.message)
})
}- สร้าง Dropdown Select สำหรับการเลือก Size ตัวอย่างเช่น
- สำหรับคนที่ใช้ mui/joy
import { Select, Option } from '@mui/joy'<div className="flex justify-end my-2">
<div>
<div>จำนวนสินค้าต่อหน้า</div>
<Select value={size} onChange={(event, newValue) => setSize(newValue)}>
<Option value={5}>5</Option>
<Option value={10}>10</Option>
<Option value={15}>15</Option>
<Option value={20}>20</Option>
</Select>
</div>
</div>- สำหรับคนที่ใช้ mui/material
import { Select, MenuItem } from '@mui/material'<div className="flex justify-end my-2">
<div>
<div>จำนวนสินค้าต่อหน้า</div>
<Select value={size} onChange={(event) => setSize(event.target.value)}>
<MenuItem value={5}>5</MenuItem>
<MenuItem value={10}>10</MenuItem>
<MenuItem value={15}>15</MenuItem>
<MenuItem value={20}>20</MenuItem>
</Select>
</div>- จากนั้นให้การเปลี่ยน Size ของเราไป Trigger UseEffect ใหม่ ด้วยการใส่ size ใน Dependency ของ UseEffect ดังนี้
useEffect(() => {
getAllProducts()
}, [size])- ลองดูผลลัพธ์ทีได้มา
