Computer >> บทช่วยสอนคอมพิวเตอร์ >  >> การเขียนโปรแกรม >> MongoDB

การยกเว้นฟิลด์ซ้อน (Nested Fields) ใน MongoDB ด้วย Aggregation Pipeline

ซ่อนฟิลด์ซ้อนในออบเจกต์ด้วย $objectToArray, $project, $arrayToObject

MongoDB ไม่รองรับ wildcard projection (เช่น "details.*.Age": 0) โดยตรงใน find() แต่สามารถทำได้ผ่าน Aggregation Pipeline โดยแปลงออบเจกต์เป็นอาร์เรย์ กรอง แล้วแปลงกลับ

ตัวอย่างข้อมูลทดสอบ

> db.demo413.insertOne({
  "_id": "101",
  "details": {
    "Info1": { "Name": "Chris", "Age": 21 },
    "Info2": { "Name": "David", "Age": 23 }
  }
});

แสดงข้อมูลก่อน

> db.demo413.find();

ผลลัพธ์:

{ "_id": "101", "details": { "Info1": { "Name": "Chris", "Age": 21 }, "Info2": { "Name": "David", "Age": 23 } } }

คำสั่ง Aggregation ซ่อนฟิลด์ Age ในทุก Sub-object

> db.demo413.aggregate([
  { $project: { "details": { $objectToArray: "$details" } } },
  { $project: { "details.v.Age": 0 } },
  { $project: { "details": { $arrayToObject: "$details" } } }
]);

ผลลัพธ์ที่ได้

{ "_id": "101", "details": { "Info1": { "Name": "Chris" }, "Info2": { "Name": "David" } } }

คำอธิบายขั้นตอน

  1. $objectToArray: "$details": แปลงออบเจกต์ details เป็นอาร์เรย์ของ key-value pairs: [{k: "Info1", v: {Name: "Chris", Age: 21}}, {k: "Info2", v: {Name: "David", Age: 23}}]
  2. { "details.v.Age": 0 }: ในโครงสร้างใหม่ details เป็นอาร์เรย์ v คือค่า (sub-object) ซ่อน Age ในทุก v
  3. $arrayToObject: "$details": แปลงอาร์เรย์กลับเป็นออบเจกต์

ข้อควรระวัง

  • วิธีนี้ใช้ได้กับออบเจกต์ระดับหนึ่ง (One level deep)
  • ถ้ามีหลายระดับ ต้อง $unwind แล้วทำซ้ำ หรือใช้ $function (MongoDB 4.4+)
  • มีค่าใช้จ่ายด้านประสิทธิภาพ (ต้องแปลงข้อมูล) เหมาะสำหรับข้อมูลไม่มาก หรือการรายงาน

ทางเลือกอื่น: ใช้ $project กำหนดฟิลด์ที่ต้องการแทน (Inclusion)

> db.demo413.aggregate([
  { $project: { _id: 1, "details.Info1.Name": 1, "details.Info2.Name": 1 } }
]);

แต่ต้องระบุ path ทุกตัวด้วยมือ