MongoDB ไม่สามารถคืนค่าเฉพาะ Embedded Document ที่ตรงเงื่อนไขได้โดยตรง การ query บนอาร์เรย์ของ Embedded Document จะคืนเอกสารทั้งฉบับที่มี element ตรงเงื่อนไข
ตัวอย่างปัญหา
1. สร้างข้อมูลที่มีอาร์เรย์ของ Embedded Document
> db.queryToEmbeddedDocument.insertOne({
"UserName": "Larry",
"PostDetails": [
{"UserMessage": "Hello", "UserLikes": 8},
{"UserMessage": "Hi", "UserLikes": 6},
{"UserMessage": "Good Morning", "UserLikes": 12},
{"UserMessage": "Awesome", "UserLikes": 4}
]
});
2. พยายามค้นหาเฉพาะโพสต์ที่ UserLikes >= 8
> db.queryToEmbeddedDocument.find(
{"PostDetails.UserLikes": { $gte: 8 }},
{ PostDetails: 1 }
).pretty();
3. ผลลัพธ์: คืนเอกสารทั้งหมด (รวมโพสต์ที่ Likes < 8)
{
"_id" : ObjectId("..."),
"PostDetails" : [
{"UserMessage": "Hello", "UserLikes": 8},
{"UserMessage": "Hi", "UserLikes": 6}, // <-- ยังคงอยู่
{"UserMessage": "Good Morning", "UserLikes": 12},
{"UserMessage": "Awesome", "UserLikes": 4} // <-- ยังคงอยู่
]
}
วิธีแก้: ใช้ Aggregation Pipeline ($unwind + $match)
db.queryToEmbeddedDocument.aggregate([
{ $unwind: "$PostDetails" },
{ $match: { "PostDetails.UserLikes": { $gte: 8 } } },
{ $project: { _id: 0, "PostDetails": 1 } }
]);
ผลลัพธ์ที่ถูกต้อง
{ "PostDetails" : { "UserMessage" : "Hello", "UserLikes" : 8 } }
{ "PostDetails" : { "UserMessage" : "Good Morning", "UserLikes" : 12 } }
สรุป
- find() คืนเอกสารทั้งฉบับ ถ้ามี element ใด element หนึ่งในอาร์เรย์ตรงเงื่อนไข
- ไม่สามารถ filter element ภายในอาร์เรย์ได้ด้วย find() ธรรมดา
- ต้องใช้ Aggregation ($unwind → $match → $project) เพื่อกรอง element ในอาร์เรย์
- MongoDB 3.6+ มี
$filterใน projection แต่ aggregation ยังยืดหยุ่นกว่า