Computer >> Hướng Dẫn Máy Tính >  >> Lập Trình >> MongoDB

Tạo mảng lồng nhau 2 cấp (double nested array) trong MongoDB

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 arrayFilters vớ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" } ] }
);