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)
- Mỗi tên là một "node", mỗi document là một "hyper-edge" nối các node
- Tìm các connected component: doc 103 (John, Jace) và 104 (Robert, John) nối nhau qua "John"
- 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ị.