Để nhóm tài liệu theo một trường và gom các giá trị của trường khác thành mảng, MongoDB sử dụng stage $group kết hợp với toán tử accumulator $push trong Aggregation Framework.
Tạo dữ liệu mẫu
> db.groupByDemo.insertOne({"UserName":"John","Subject":"MongoDB"});
{ "acknowledged" : true, "insertedId" : ObjectId("5cd69f0457806ebf1256f136") }
> db.groupByDemo.insertOne({"UserName":"Larry","Subject":"MySQL"});
{ "acknowledged" : true, "insertedId" : ObjectId("5cd69f0657806ebf1256f137") }
> db.groupByDemo.insertOne({"UserName":"John","Subject":"Java"});
{ "acknowledged" : true, "insertedId" : ObjectId("5cd69f0d57806ebf1256f138") }
> db.groupByDemo.insertOne({"UserName":"John","Subject":"C"});
{ "acknowledged" : true, "insertedId" : ObjectId("5cd69f1357806ebf1256f139") }
> db.groupByDemo.insertOne({"UserName":"Larry","Subject":"SQL Server"});
{ "acknowledged" : true, "insertedId" : ObjectId("5cd69f1c57806ebf1256f13a") }
Xem dữ liệu
> db.groupByDemo.find().pretty();
Nhóm theo UserName và gom Subject thành mảng
> db.groupByDemo.aggregate({$group: { '_id': '$UserName', 'Subject': { $push: '$Subject' }}});Kết quả
Giải thích
_id: '$UserName': Khóa nhóm (group key) - nhóm theo trường UserName$push: '$Subject': Đẩy giá trị Subject của mỗi tài liệu vào mảng kết quả- Thứ tự trong mảng tuân theo thứ tự tài liệu xuất hiện trong collection (không đảm bảo sort)
Các biến thể hữu ích
1. $addToSet - Loại bỏ trùng lặp
db.groupByDemo.aggregate({$group: {_id: '$UserName', Subject: {$addToSet: '$Subject'}}});
2. Sắp xếp trong mảng kết quả
db.groupByDemo.aggregate([
{$sort: {Subject: 1}}, // Sort trước khi push
{$group: {_id: '$UserName', Subject: {$push: '$Subject'}}}
]);
3. Thêm nhiều trường vào kết quả
db.groupByDemo.aggregate([
{$group: {
_id: '$UserName',
Subjects: {$push: '$Subject'},
Count: {$sum: 1},
FirstSubject: {$first: '$Subject'},
LastSubject: {$last: '$Subject'}
}}
]);
4. Giữ lại _id gốc của tài liệu
db.groupByDemo.aggregate([
{$group: {_id: '$UserName', Docs: {$push: '$$ROOT'}}}
]);
Lưu ý hiệu năng
- Tạo index trên trường group key:
db.groupByDemo.createIndex({UserName: 1}) $pushcó giới hạn 16MB cho document kết quả (BSON limit)- Với dữ liệu lớn, cân nhắc
allowDiskUse: true