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

รวม Multiple Arrays เป็น Single Array ใน MongoDB Aggregate

การรวมหลาย array fields ในเอกสารเดียวกันให้กลายเป็น array เดียว ทำได้ด้วย $setUnion ร่วม $filter ใน $project stage

สร้างคอลเลกชันและข้อมูลตัวอย่าง

> db.demo119.insertOne({
  "_id": 101,
  "WebDetails": [
    { "ImagePath": "/all/image1", "isCorrect": "false" },
    { "ImagePath": "/all/image2", "isCorrect": "true" }
  ],
  "ClientDetails": [
    { "Name": "Chris", "isCorrect": "false" },
    { "Name": "David", "isCorrect": "true" }
  ]
});
{ "acknowledged" : true, "insertedId" : 101 }

แสดงข้อมูล

> db.demo119.find();

ผลลัพธ์: มี WebDetails และ ClientDetails arrays

Query รวม Arrays และ Filter isCorrect="false"

> db.demo119.aggregate([
  { "$project": {
    "AllDetails": {
      "$filter": {
        "input": {
          "$setUnion": [
            { "$ifNull": ["$WebDetails", []] },
            { "$ifNull": ["$ClientDetails", []] }
          ]
        },
        "as": "out",
        "cond": { "$eq": ["$$out.isCorrect", "false"] }
      }
    }
  }},
  { "$match": { "AllDetails.0": { "$exists": true } } }
])

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

  1. $ifNull: ["$WebDetails", []]: ป้องกัน error หาก field หายไป (คืน array ว่าง)
  2. $setUnion: รวม 2 arrays เป็น array เดียว (ลบ duplicate ตาม object ทั้งหมด)
  3. $filter: กรองเฉพาะ element ที่ isCorrect="false"
  4. $match: {"AllDetails.0": {$exists: true}}: กรองเอกสารที่ AllDetails ไม่ว่าง

ผลลัพธ์

{ "_id" : 101, "AllDetails" : [
  { "ImagePath" : "/all/image1", "isCorrect" : "false" },
  { "Name" : "Chris", "isCorrect" : "false" }
] }

รวม image1 (จาก WebDetails) และ Chris (จาก ClientDetails) ที่ isCorrect="false"

ข้อควรระวังของ $setUnion

  • ลบ duplicate ตาม object ทั้งหมด (ทุก field ตรงกัน)
  • ไม่ preserve order
  • หาก object structure ต่างกัน (ImagePath vs Name) จะไม่ถูกลบซ้ำ

วิธีอื่น: $concatArrays (MongoDB 4.4+) - รวมโดยไม่ลบซ้ำ

db.demo119.aggregate([
  { $project: {
    AllDetails: {
      $filter: {
        input: { $concatArrays: ["$WebDetails", "$ClientDetails"] },
        cond: { $eq: ["$$this.isCorrect", "false"] }
      }
    }
  }}
])

กรณีต้องการ Merge Objects (รวม field)

หาก array ทั้งสองมีโครงสร้างเดียวกัน และต้องการ merge โดย key:

db.collection.aggregate([
  { $project: {
    merged: {
      $reduce: {
        input: { $concatArrays: ["$array1", "$array2"] },
        initialValue: {},
        in: { $mergeObjects: ["$$value", "$$this"] }
      }
    }
  }}
])

สรุป: $setUnion + $filter = รวมและกรอง | $concatArrays + $filter = รวมทุกอย่างแล้วกรอง