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

Gộp hai danh sách nếu có ít nhất một phần tử trùng khớp MongoDB

Gom nhóm các document có phần tử chung trong mảng (Graph-like grouping)

Bài toán: Tìm các nhóm document mà mảng StudentName của chúng có ít nhất 1 phần tử trùng nhau. Đây là bài toán tìm connected components trên đồ thị.

1. Dữ liệu: 4 document, mảng StudentName

> db.demo456.insertOne({ _id: 101, StudentName: ["Chris", "David"] });
> db.demo456.insertOne({ _id: 102, StudentName: ["Mike", "Sam"] });
> db.demo456.insertOne({ _id: 103, StudentName: ["John", "Jace"] });
> db.demo456.insertOne({ _id: 104, StudentName: ["Robert", "John"] });

2. Pipeline phức tạp (Connected Components)

> db.demo456.aggregate([
    { $unwind: "$StudentName" },                              // 1: Tách mảng thành (doc, name)
    { $group: { _id: "$StudentName", combine: { $addToSet: "$_id" }, size: { $sum: 1 } } }, // 2: Gom theo tên
    { $match: { size: { $gt: 1 } } },                         // 3: Chỉ giữ tên xuất hiện >1 lần
    { $project: { _id: 1, combine: 1, size: 1, combine1: "$combine" } },
    { $unwind: "$combine" },                                  // 4: Tách mảng combine
    { $unwind: "$combine1" },                                 // 5: Tách mảng combine1 (self-join)
    { $group: { _id: "$combine", l: { $first: "$_id" }, size: { $sum: 1 }, set: { $addToSet: "$combine1" } } }, // 6: Gom theo doc id
    { $sort: { size: 1 } },
    { $group: { _id: "$l", combineIds: { $last: "$set" }, size: { $sum: 1 } } }, // 7: Gom nhóm cuối
    { $match: { size: { $gt: 1 } } }                          // 8: Chỉ nhóm có >1 doc
]);

3. Kết quả

{ "_id": "John", "combineIds": [103, 104], "size": 2 }

Giải thích logic (đơn giản hóa)

  1. Mỗi tên là một "node", mỗi document là một "hyper-edge" nối các node
  2. Tìm các connected component: doc 103 (John, Jace) và 104 (Robert, John) nối nhau qua "John"
  3. Kết quả: Nhóm {103, 104} liên kết qua "John"

Cách tiếp cận hiện đại hơn (MongoDB 5.0+): $graphLookup

db.demo456.aggregate([
    {
        $graphLookup: {
            from: "demo456",
            startWith: "$StudentName",
            connectFromField: "StudentName",
            connectToField: "StudentName",
            as: "connected",
            maxDepth: 10
        }
    },
    { $project: { group: { $setUnion: ["$StudentName", "$connected.StudentName"] } } }
]);

Lưu ý: Pipeline gốc rất phức tạp và khó maintain. Với MongoDB 3.4+, $graphLookup là giải pháp chuẩn cho bài toán đồ thị.