กรองเอกสารที่ทุกสมาชิกใน Nested Array ผ่านเงื่อนไขด้วย Aggregation
เมื่อต้องการหาเอกสารที่ ทุกองค์ประกอบ ในอาร์เรย์ซ้อน (Nested Array) ตรงตามเงื่อนไข (เช่น CountryName = "US" ทุกตัว) ให้ใช้ Aggregation Pipeline พร้อม $unwind, $group, และ $cond
ตัวอย่างข้อมูลทดสอบ
> db.demo418.insertOne({
"details": [
{ "CountryName": "US", "Marks": 45 },
{ "CountryName": "US", "Marks": 56 }
],
"Name": "John"
});
> db.demo418.insertOne({
"details": [
{ "CountryName": "US", "Marks": 78 },
{ "CountryName": "UK", "Marks": 97 }
],
"Name": "Mike"
});
แสดงข้อมูลทั้งหมด
> db.demo418.find();
ผลลัพธ์:
{ "_id": ObjectId("..."), "details": [{ "CountryName": "US", "Marks": 45 }, { "CountryName": "US", "Marks": 56 }], "Name": "John" }
{ "_id": ObjectId("..."), "details": [{ "CountryName": "US", "Marks": 78 }, { "CountryName": "UK", "Marks": 97 }], "Name": "Mike" }
คำสั่ง Aggregation กรองเอกสารที่ details ทุกตัวเป็น US
> db.demo418.aggregate([
{ $unwind: "$details" },
{ $group: {
_id: "$_id",
details: { $first: "$details" },
alldetails: { $sum: 1 },
alldetailsmatch: { $sum: { $cond: [{ $eq: ["$details.CountryName", "US"] }, 1, 0] } },
Name: { $first: "$Name" }
}},
{ $project: {
_id: 1, Name: 1, details: 1,
arrayValue: { $cond: [{ $eq: ["$alldetails", "$alldetailsmatch"] }, 1, 0] }
}},
{ $match: { 'arrayValue': 1 } }
]);
ผลลัพธ์ที่ได้ (เฉพาะ John ที่ทุก details เป็น US)
{ "_id": ObjectId("..."), "details": { "CountryName": "US", "Marks": 45 }, "Name": "John", "arrayValue": 1 }
คำอธิบายขั้นตอน
- $unwind: "$details": แยกอาร์เรย์ details ให้แต่ละออบเจกต์เป็นเอกสารแยกกัน
- $group: รวมกลับตาม _id เดิม นับจำนวนทั้งหมด (alldetails) และนับที่ match US (alldetailsmatch)
- $project: สร้าง arrayValue = 1 ถ้า alldetails == alldetailsmatch (ทุกตัว match)
- $match: { arrayValue: 1 }: กรองเอกสารที่ทุกตัว match
วิธีที่ง่ายกว่า (MongoDB 3.6+): ใช้ $all หรือ $not + $elemMatch
> // หาเอกสารที่ details ทุกตัวเป็น US
> db.demo418.find({ "details.CountryName": { $not: { $elemMatch: { $ne: "US" } } } });
หรือใช้ $all สำหรับค่าที่ต้องมีทั้งหมด (แตกต่างจาก "ทุกตัวเป็นค่านั้น")