MongoDB cho phép lồng mảng trong mảng (array of arrays of objects) tự do. Cấu trúc phù hợp cho dữ liệu phân cấp như: Student -> Projects -> Technologies.
Ví dụ minh họa
Tạo collection doubleNestedArrayDemo:
> db.doubleNestedArrayDemo.insertOne({
"StudentId": "1000",
"StudentName": "Larry",
"StudentDetails": [
{
"ProjectName": "Online Banking",
"ProjectDetails": [
{ "TechnologyUsed": "Java" },
{ "TechnologyUsed": "MySQL in Backend" }
]
}
]
});
> db.doubleNestedArrayDemo.insertOne({
"StudentId": "1001",
"StudentName": "Robert",
"StudentDetails": [
{
"ProjectName": "Student Web Tracker",
"ProjectDetails": [
{ "TechnologyUsed": "Django Framework" },
{ "TechnologyUsed": "MongoDB in Backend" }
]
}
]
});
Hiển thị tất cả:
> db.doubleNestedArrayDemo.find().pretty()
Kết quả:
{
"_id" : ObjectId("..."),
"StudentId" : "1000",
"StudentName" : "Larry",
"StudentDetails" : [
{
"ProjectName" : "Online Banking",
"ProjectDetails" : [
{ "TechnologyUsed" : "Java" },
{ "TechnologyUsed" : "MySQL in Backend" }
]
}
]
}
{
"_id" : ObjectId("..."),
"StudentId" : "1001",
"StudentName" : "Robert",
"StudentDetails" : [
{
"ProjectName" : "Student Web Tracker",
"ProjectDetails" : [
{ "TechnologyUsed" : "Django Framework" },
{ "TechnologyUsed" : "MongoDB in Backend" }
]
}
]
}
Truy vấn dữ liệu lồng 2 cấp
1. Tìm sinh viên có project dùng "Java" (dot notation + $elemMatch)
// Cách 1: $elemMatch lồng (chính xác nhất cho mảng object)
db.doubleNestedArrayDemo.find({
"StudentDetails": {
$elemMatch: {
"ProjectDetails": { $elemMatch: { "TechnologyUsed": "Java" } }
}
}
});
// Cách 2: Dot notation đơn giản (có thể false positive nếu nhiều project)
db.doubleNestedArrayDemo.find({ "StudentDetails.ProjectDetails.TechnologyUsed": "Java" });
2. Aggregation: Unwind 2 cấp để flatten
db.doubleNestedArrayDemo.aggregate([
{ $unwind: "$StudentDetails" },
{ $unwind: "$StudentDetails.ProjectDetails" },
{ $project: {
StudentId: 1, StudentName: 1,
ProjectName: "$StudentDetails.ProjectName",
Technology: "$StudentDetails.ProjectDetails.TechnologyUsed"
}}
]);
Kết quả flatten:
{ "StudentId": "1000", "StudentName": "Larry", "ProjectName": "Online Banking", "Technology": "Java" }
{ "StudentId": "1000", "StudentName": "Larry", "ProjectName": "Online Banking", "Technology": "MySQL in Backend" }
{ "StudentId": "1001", "StudentName": "Robert", "ProjectName": "Student Web Tracker", "Technology": "Django Framework" }
{ "StudentId": "1001", "StudentName": "Robert", "ProjectName": "Student Web Tracker", "Technology": "MongoDB in Backend" }
Lưu ý thiết kế
- Độ sâu: MongoDB hỗ trợ lồng tới **100 cấp** (giới hạn BSON depth), nhưng thực tế nên hạn chế <= 2-3 cấp.
- Kích thước document: Max 16MB. Mảng lồng lớn dễ vượt giới hạn.
- Index: Không thể tạo index trực tiếp trên field sâu 2 cấp trong mảng (ví dụ:
StudentDetails.ProjectDetails.TechnologyUsed). Cần flatten hoặc dùng text search. - Update: Dùng
arrayFiltersvới$[outer],$[inner](MongoDB 3.6+) để cập nhật chính xác phần tử lồng.
Ví dụ update với arrayFilters (MongoDB 3.6+)
// Thêm technology "Redis" vào project "Online Banking" của Larry
db.doubleNestedArrayDemo.updateOne(
{ StudentId: "1000" },
{ $push: { "StudentDetails.$[outer].ProjectDetails": { TechnologyUsed: "Redis" } } },
{ arrayFilters: [ { "outer.ProjectName": "Online Banking" } ] }
);