การหาค่าเฉลี่ย (Average) ของฟิลด์ทั้งหมดด้วย Aggregation Framework ใน MongoDB
ใช้ $avg operator ภายใน $group stage ของ Aggregation Pipeline เพื่อคำนวณค่าเฉลี่ยของฟิลด์ตัวเลขทั้งหมดใน Collection
ตัวอย่างการสร้างคอลเลกชันและเพิ่มข้อมูล
> db.averageAggregationDemo.insertOne({"PlayerGameScore":45});
{ "acknowledged" : true, "insertedId" : ObjectId("5c9ed66bd628fa4220163b95") }
> db.averageAggregationDemo.insertOne({"PlayerGameScore":55});
{ "acknowledged" : true, "insertedId" : ObjectId("5c9ed671d628fa4220163b96") }
> db.averageAggregationDemo.insertOne({"PlayerGameScore":65});
{ "acknowledged" : true, "insertedId" : ObjectId("5c9ed676d628fa4220163b97") }
> db.averageAggregationDemo.insertOne({"PlayerGameScore":35});
{ "acknowledged" : true, "insertedId" : ObjectId("5c9ed67bd628fa4220163b98") }
> db.averageAggregationDemo.insertOne({"PlayerGameScore":16});
{ "acknowledged" : true, "insertedId" : ObjectId("5c9ed701d628fa4220163b99") }
แสดงข้อมูลทั้งหมด
> db.averageAggregationDemo.find().pretty();
ผลลัพธ์:
{ "_id" : ObjectId("5c9ed66bd628fa4220163b95"), "PlayerGameScore" : 45 }
{ "_id" : ObjectId("5c9ed671d628fa4220163b96"), "PlayerGameScore" : 55 }
{ "_id" : ObjectId("5c9ed676d628fa4220163b97"), "PlayerGameScore" : 65 }
{ "_id" : ObjectId("5c9ed67bd628fa4220163b98"), "PlayerGameScore" : 35 }
{ "_id" : ObjectId("5c9ed701d628fa4220163b99"), "PlayerGameScore" : 16 }
คำนวณค่าเฉลี่ยของ PlayerGameScore ทั้งหมด
> db.averageAggregationDemo.aggregate({
"$group": {
"_id": null,
"PlayerGameScoreAverage": { "$avg": "$PlayerGameScore" }
}
});
ผลลัพธ์:
{ "_id" : null, "PlayerGameScoreAverage" : 43.2 }
การคำนวณ: (45 + 55 + 65 + 35 + 16) / 5 = 216 / 5 = 43.2
คำอธิบาย Pipeline Stages
- $group : จับกลุ่มเอกสาร
- "_id": null : จับกลุ่มทั้งหมดเป็นกลุ่มเดียว (Global Aggregation)
- $avg : คำนวณค่าเฉลี่ยของ Expression ที่ระบุ
- "$PlayerGameScore" : อ้างอิง Field PlayerGameScore ของแต่ละ Document
ตัวอย่างขั้นสูง: Group By Field แล้วหาค่าเฉลี่ยแต่ละกลุ่ม
> db.averageAggregationDemo.insertMany([
{ "PlayerName": "John", "PlayerGameScore": 45, "GameType": "Action" },
{ "PlayerName": "Jane", "PlayerGameScore": 55, "GameType": "Action" },
{ "PlayerName": "Bob", "PlayerGameScore": 65, "GameType": "Puzzle" },
{ "PlayerName": "Alice", "PlayerGameScore": 35, "GameType": "Puzzle" }
]);
> db.averageAggregationDemo.aggregate([
{ $group: {
_id: "$GameType",
averageScore: { $avg: "$PlayerGameScore" },
count: { $sum: 1 },
maxScore: { $max: "$PlayerGameScore" },
minScore: { $min: "$PlayerGameScore" }
}}
]);
ผลลัพธ์:
{ "_id" : "Action", "averageScore" : 50, "count" : 2, "maxScore" : 55, "minScore" : 45 }
{ "_id" : "Puzzle", "averageScore" : 50, "count" : 2, "maxScore" : 65, "minScore" : 35 }
Accumulator Operators อื่นๆ ใน $group
| Operator | คำอธิบาย | ตัวอย่าง |
|---|---|---|
| $avg | ค่าเฉลี่ย | { $avg: "$score" } |
| $sum | ผลรวม / นับจำนวน | { $sum: "$score" } หรือ { $sum: 1 } |
| $min | ค่าต่ำสุด | { $min: "$score" } |
| $max | ค่าสูงสุด | { $max: "$score" } |
| $first | ค่าแรกในกลุ่ม | { $first: "$score" } |
| $last | ค่าสุดท้ายในกลุ่ม | { $last: "$score" } |
| $push | สร้าง Array ของค่าทั้งหมด | { $push: "$score" } |
| $addToSet | สร้าง Array ของค่า Unique | { $addToSet: "$score" } |
| $stdDevPop | Standard Deviation (Population) | { $stdDevPop: "$score" } |
| $stdDevSamp | Standard Deviation (Sample) | { $stdDevSamp: "$score" } |
การจัดการค่า Null/Missing
- $avg : ข้ามค่า null และ missing field อัตโนมัติ (ไม่นับในตัวส่วน)
- $sum : ข้าม null/missing เช่นกัน
- ถ้าต้องการนับ null เป็น 0 ใช้
$ifNull:{ $avg: { $ifNull: ["$score", 0] } }
Best Practices
- ใช้ _id: null สำหรับ Global Aggregation (ทั้ง Collection)
- รวม
$matchก่อน $group เพื่อ Filter ข้อมูลก่อนคำนวณ (ลด Workload) - สร้าง Index บน Field ที่ Group By เพื่อเร่งการ Sort/Group
- ใช้
allowDiskUse: trueถ้าข้อมูลเยอะเกิน Memory Limit (100MB)
// ตัวอย่าง Pipeline ครบถ้วน
db.collection.aggregate([
{ $match: { "status": "active", "date": { $gte: ISODate("2024-01-01") } } },
{ $group: {
_id: null,
avgScore: { $avg: "$score" },
total: { $sum: 1 }
}},
{ $project: { _id: 0, avgScore: 1, total: 1 } }
], { allowDiskUse: true });