ใช้ Aggregation Pipeline: $group + $sort + $skip + $limit
เมื่อต้องการค่าที่ไม่ซ้ำ (Distinct) เรียงลำดับ (Sorted) และแบ่งหน้า (Skip/Limit) ใช้ Aggregation แทน distinct() เพราะ distinct() ไม่รองรับ Sort/Skip/Limit โดยตรง
ตัวอย่างข้อมูล: ชื่อซ้ำกัน
> db.orderedDistinctDemo.insertOne({"Name":"John"});
> db.orderedDistinctDemo.insertOne({"Name":"Larry"});
> db.orderedDistinctDemo.insertOne({"Name":"Larry"});
> db.orderedDistinctDemo.insertOne({"Name":"Sam"});
> db.orderedDistinctDemo.insertOne({"Name":"John"});
> db.orderedDistinctDemo.insertOne({"Name":"Carol"});
> db.orderedDistinctDemo.insertOne({"Name":"David"});
> db.orderedDistinctDemo.insertOne({"Name":"Carol"});
Pipeline: Distinct → Sort → Skip 3 → Limit 8
> db.orderedDistinctDemo.aggregate([
{ $group: { _id: "$Name" } }, // Distinct: Group by Name
{ $sort: { _id: 1 } }, // Sort by Name Ascending
{ $skip: 3 }, // ข้าม 3 ตัวแรก
{ $limit: 8 } // เอาสูงสุด 8 ตัว
]);
ผลลัพธ์
{ "_id" : "Larry" }
{ "_id" : "Sam" }
คำอธิบายลำดับ
- Distinct Values (Sorted): Carol, David, John, Larry, Sam
- Skip 3: ข้าม Carol, David, John
- Limit 8: เอาที่เหลือ (Larry, Sam) - มีแค่ 2 ตัว
เปรียบเทียบกับ distinct()
// distinct() - ไม่รองรับ Sort/Skip/Limit
db.orderedDistinctDemo.distinct("Name")
// Result: [ "John", "Larry", "Sam", "Carol", "David" ] (ลำดับไม่ประมาณ)
Aggregation Operators สำหรับ Pagination
| Stage | วัตถุประสงค์ |
|---|---|
$group: { _id: "$field" } | Distinct (Unique Values) |
$sort: { _id: 1 } | Sort Ascending |
$sort: { _id: -1 } | Sort Descending |
$skip: n | ข้าม n Documents |
$limit: n | จำกัด n Documents |
Performance Tips
- สร้าง Index บนฟิลด์ที่ Group/Sort:
db.coll.createIndex({ Name: 1 }) - $group + $sort ใช้ Index ได้ถ้า Pattern ตรงกัน
- Skip มาก (Deep Paging) ช้า - ใช้ Range-based Pagination แทน (Filter by Last Seen Value)