รวมค่า Unique จากอาร์เรย์หลายชุดในคอลเลกชันต่างกันด้วย $setUnion และ $addToSet
เมื่อต้องการรวมค่าที่ไม่ซ้ำกัน (Unique Values) จากอาร์เรย์ในหลายเอกสารหรือหลายฟิลด์ ให้ใช้ Aggregation Pipeline พร้อม $setUnion, $concatArrays, และ $addToSet
ตัวอย่างข้อมูลทดสอบ (2 เอกสาร ฟิลด์ต่างกัน)
> db.demo420.insert({ "details": [{ "Value1": 10, "Value2": 20, "Value3": 30 }] });
> db.demo420.insert({ "Info": [{ "Value1": 10, "Value2": 20, "Value3": 300 }] });
แสดงข้อมูล
> db.demo420.find();
ผลลัพธ์:
{ "_id": ObjectId("..."), "details": [{ "Value1": 10, "Value2": 20, "Value3": 30 }] }
{ "_id": ObjectId("..."), "Info": [{ "Value1": 10, "Value2": 20, "Value3": 300 }] }
คำสั่ง Aggregation รวมค่า Unique จากทั้งสองฟิลด์
> db.demo420.aggregate([
{ $project: {
_id: 0,
unique: {
$filter: {
input: {
$setDifference: [
{ $concatArrays: ["$Info.Value1", "$Info.Value2", "$Info.Value3"] },
[]
]
},
cond: { $ne: ["$$this", ""] }
}
}
}},
{ $unwind: "$unique" },
{ $group: { _id: null, uniqueArray: { $addToSet: "$unique" } } }
]);
ผลลัพธ์ที่ได้
{ "_id": null, "uniqueArray": [300, 20, 10] }
คำอธิบายขั้นตอน (ซับซ้อนเนื่องจากโครงสร้างข้อมูล)
- $concatArrays: รวมอาร์เรย์ Value1, Value2, Value3 ของฟิลด์ Info เข้าด้วยกัน
- $setDifference: [combined, []]: ลบค่าว่าง (แต่ที่นี่ไม่มีผลเพราะไม่มีค่าว่าง)
- $filter: กรองค่าว่าง (cond: $$this != "")
- $unwind: แยกอาร์เรย์ unique เป็นเอกสารต่อเอกสาร
- $group + $addToSet: รวมค่าที่ไม่ซ้ำกันกลับเป็นอาร์เรย์ uniqueArray
วิธีที่ง่ายกว่า (ถ้าข้อมูลอยู่ในฟิลด์เดียวกัน)
> db.collection.aggregate([
{ $unwind: "$arrayField" },
{ $group: { _id: null, uniqueValues: { $addToSet: "$arrayField" } } }
]);
ตัวดำเนินการเซต (Set Operators) สำหรับอาร์เรย์
| Operator | คำอธิบาย |
|---|---|
| $setUnion | รวมอาร์เรย์ทั้งหมด ไม่ซ้ำ (Union) |
| $setIntersection | ค่าที่ซ้ำในทุกอาร์เรย์ (Intersection) |
| $setDifference | ค่าในอาร์เรย์แรก ที่ไม่อยู่ในอาร์เรย์อื่น (Difference) |