Sử dụng Aggregation Pipeline ($group + $match) để tìm các giá trị field xuất hiện nhiều hơn 1 lần.
Pipeline chuẩn
db.collection.aggregate([
{ $group: { _id: "$tênTrường", count: { $sum: 1 } } },
{ $match: { count: { $gt: 1 } } },
{ $sort: { count: -1 } } // Tùy chọn: sắp xếp theo số lượng giảm dần
]);
Ví dụ minh họa
Tạo collection findAllNonDistinctDemo với nhiều UserName trùng:
> db.findAllNonDistinctDemo.insertOne({ "UserName": "John", "UserAge": 28 });
> db.findAllNonDistinctDemo.insertOne({ "UserName": "Larry", "UserAge": 21 });
> db.findAllNonDistinctDemo.insertOne({ "UserName": "Larry", "UserAge": 23 });
> db.findAllNonDistinctDemo.insertOne({ "UserName": "David", "UserAge": 22 });
> db.findAllNonDistinctDemo.insertOne({ "UserName": "John", "UserAge": 26 });
> db.findAllNonDistinctDemo.insertOne({ "UserName": "Robert", "UserAge": 24 });
> db.findAllNonDistinctDemo.insertOne({ "UserName": "Robert", "UserAge": 25 });
> db.findAllNonDistinctDemo.insertOne({ "UserName": "Mike", "UserAge": 29 });
Hiển thị tất cả:
> db.findAllNonDistinctDemo.find().pretty();
Tìm UserName trùng lặp
> db.findAllNonDistinctDemo.aggregate([
{ $group: { _id: "$UserName", Counter: { $sum: 1 } } },
{ $match: { Counter: { $gt: 1 } } }
]).pretty();
Kết quả:
{ "_id" : "Robert", "Counter" : 2 }
{ "_id" : "Larry", "Counter" : 2 }
{ "_id" : "John", "Counter" : 2 }
Mở rộng: Lấy cả _id của các document trùng
db.findAllNonDistinctDemo.aggregate([
{ $group: { _id: "$UserName", ids: { $push: "$_id" }, count: { $sum: 1 } } },
{ $match: { count: { $gt: 1 } } },
{ $project: { _id: 0, UserName: "$_id", count: 1, ids: 1 } }
]);
Kết quả:
{ "UserName" : "Robert", "count" : 2, "ids" : [ ObjectId("..."), ObjectId("...") ] }
{ "UserName" : "Larry", "count" : 2, "ids" : [ ObjectId("..."), ObjectId("...") ] }
{ "UserName" : "John", "count" : 2, "ids" : [ ObjectId("..."), ObjectId("...") ] }
Xử lý trùng lặp (Deduplication)
Giữ 1 document (thường là _id nhỏ nhất/đầu tiên), xóa các bản còn lại:
db.findAllNonDistinctDemo.aggregate([
{ $sort: { _id: 1 } },
{ $group: { _id: "$UserName", docId: { $first: "$_id" }, dupIds: { $push: "$_id" } } },
{ $match: { $expr: { $gt: [{ $size: "$dupIds" }, 1] } } },
{ $project: { _id: 0, idsToDelete: { $slice: ["$dupIds", 1, { $size: "$dupIds" }] } } }
]).forEach(doc => {
db.findAllNonDistinctDemo.deleteMany({ _id: { $in: doc.idsToDelete } });
});
Phòng ngừa: Unique Index
db.collection.createIndex({ "UserName": 1 }, { unique: true });
Tạo index này sẽ **chặn insert/update** tạo ra duplicate. Nếu dữ liệu đã có duplicate, phải dọn dẹp trước khi tạo index.