เลือก สร้าง และแปลงฟิลด์ด้วย $project ใน Aggregation Pipeline
Stage $project ใช้สำหรับควบคุมฟิลด์ที่จะส่งต่อไปใน Pipeline: เลือกฟิลด์ (Include/Exclude), สร้างฟิลด์ใหม่, คำนวณค่า, เปลี่ยนชื่อฟิลด์ ฯลฯ
ตัวอย่างข้อมูลทดสอบ (มีโครงสร้าง MarksInformation ต่างกัน)
> db.demo439.insertOne({ "Name": "Chris", "MarksInformation": { "Marks1": 67, "Marks2": 45, "Marks3": 78 } });
> db.demo439.insertOne({ "Name": "David", "MarksInformation": { "Marks1": 50, "Marks2": 57, "Marks3": 68 } });
> db.demo439.insertOne({ "Name": "Bob", "MarksInformation": { "Score1": 65, "Score2": 71 } });
แสดงข้อมูล
> db.demo439.find();
ผลลัพธ์: Chris, David มี Marks1-3; Bob มี Score1-2 (ไม่มี Marks3)
คำสั่ง $project แปลงให้โครงสร้างเดียวกัน (Normalize)
> db.demo439.aggregate({
$project: {
"Name": 1,
"Marks1": {
$cond: [
{ $eq: [{ $ifNull: ["$MarksInformation.Marks1", 0] }, 0] },
{ $ifNull: ["$MarksInformation.Score1", 0] },
"$MarksInformation.Marks1"
]
},
"Marks2": {
$cond: [
{ $eq: [{ $ifNull: ["$MarksInformation.Marks2", 0] }, 0] },
{ $ifNull: ["$MarksInformation.Score2", 0] },
"$MarksInformation.Marks2"
]
},
"Marks3": {
$cond: [
{ $eq: [{ $ifNull: ["$MarksInformation.Marks3", 0] }, 0] },
{ $ifNull: ["$MarksInformation.Score3", 0] },
"$MarksInformation.Marks3"
]
}
}
});
ผลลัพธ์ที่ได้ (โครงสร้างเดียวกันทุกเอกสาร)
{ "_id": ObjectId("..."), "Name": "Chris", "Marks1": 67, "Marks2": 45, "Marks3": 78 }
{ "_id": ObjectId("..."), "Name": "David", "Marks1": 50, "Marks2": 57, "Marks3": 68 }
{ "_id": ObjectId("..."), "Name": "Bob", "Marks1": 65, "Marks2": 71, "Marks3": 0 }
คำอธิบาย Logic
- $ifNull: ["$MarksInformation.Marks1", 0]: ถ้า Marks1 มีค่า ใช้ค่านั้น มิฉะนั้น 0
- $eq: [..., 0]: ตรวจสอบว่าผลลัพธ์เป็น 0 หรือไม่ (หมายถึง Marks1 ไม่มี/เป็น 0)
- $cond: [isZero, fallbackScore, originalMarks]: ถ้า Marks1 ไม่มี/เป็น 0 -> ใช้ Score1 แทน (ถ้ามี) มิฉะนั้นใช้ Marks1
- Bob ไม่มี Marks3 และ Score3 -> ได้ 0
ฟีเจอร์ $project อื่นๆ ที่น่าสนใจ
| Feature | ตัวอย่าง |
|---|---|
| Include/Exclude | { name: 1, _id: 0 } |
| Rename Field | { fullName: "$name" } |
| Computed Field | { total: { $add: ["$price", "$tax"] } } |
| Array Operations | { firstItem: { $arrayElemAt: ["$items", 0] } } |
| Date Operations | { year: { $year: "$date" } } |
ข้อแตกต่าง $project (Aggregation) vs Projection (find)
- find() Projection: 1/0 เท่านั้น ไม่คำนวณค่าใหม่ได้
- $project: คำนวณ, แปลง, สร้างฟิลด์ใหม่ได้ครบครัน