Để tìm tài liệu mà **tất cả** phần tử trong mảng lồng nhau (nested array) đều thỏa mãn một điều kiện (logic ALL), bạn không thể dùng `find()` đơn giản (vì `find` chỉ cần **một** phần tử khớp). Cần dùng **Aggregation Pipeline** để "bật mở" mảng ($unwind), kiểm tra từng phần tử, gom nhóm lại và so sánh số lượng.
1. Tạo dữ liệu: 2 user, mỗi user có mảng details (CountryName, Marks)
> 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"
});
2. Mục tiêu: Chỉ lấy user mà **TẤT CẢ** details đều có CountryName = "US"
-> Chỉ John thỏa (Mike có 1 UK).
3. Aggregation Pipeline phức tạp
> db.demo418.aggregate([
{ $unwind: "$details" }, // Bật mảng details thành nhiều dòng
{
$group: {
_id: "$_id",
details: { $first: "$details" }, // Giữ 1 mẫu details
alldetails: { $sum: 1 }, // Tổng số phần tử details
alldetailsmatch: { // Đếm phần tử có CountryName = "US"
$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 } } // Chỉ giữ where ALL match
]);
4. Kết quả
{ "_id": ObjectId("..."), "details": { "CountryName": "US", "Marks": 45 }, "Name": "John", "arrayValue": 1 }
Cách đơn giản hơn (MongoDB 3.6+): Dùng $not + $elemMatch (trong find)
Logic: "KHÔNG TỒN TẠI phần tử nào KHÔNG thỏa mãn" = "TẤT CẢ đều thỏa mãn".
db.demo418.find({
$not: {
details: { $elemMatch: { CountryName: { $ne: "US" } } }
}
});
Cách này ngắn gọn, dễ hiểu, và dùng được index.