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

Xóa bản ghi trùng lặp trong MongoDB 3.x (Aggregation)

Để phát hiện và xóa các tài liệu trùng lặp (dựa trên giá trị trường, không phải _id) trong MongoDB 3.x (trước khi có deleteMany với filter phức tạp), cách phổ biến là dùng Aggregation $group để tìm nhóm trùng lặp, lấy danh sách _id, rồi xóa thủ công các _id thừa.

1. Tạo dữ liệu có trùng FirstName

> db.demo438.insertOne({ "FirstName": "Chris" });
> db.demo438.insertOne({ "FirstName": "David" });
> db.demo438.insertOne({ "FirstName": "Chris" });  // Trùng
> db.demo438.insertOne({ "FirstName": "Bob" });
> db.demo438.insertOne({ "FirstName": "David" }); // Trùng

2. Aggregation: Nhóm theo FirstName, gom _id

> db.demo438.aggregate([
    { $group: { _id: { FirstName: "$FirstName" }, DuplicateValueIds: { $addToSet: "$_id" } } }
]);

3. Kết quả: Các nhóm trùng có mảng _id > 1 phần tử

{ "_id": { "FirstName": "David" }, "DuplicateValueIds": [ ObjectId("5e775c47..."), ObjectId("5e775c3d...") ] }
{ "_id": { "FirstName": "Bob" }, "DuplicateValueIds": [ ObjectId("5e775c44...") ] }
{ "_id": { "FirstName": "Chris" }, "DuplicateValueIds": [ ObjectId("5e775c40..."), ObjectId("5e775c37...") ] }

4. Xóa thủ công (logic: giữ _id đầu tiên, xóa các _id còn lại)

// Ví dụ xóa David trùng (giữ ObjectId("5e775c3d..."))
db.demo438.deleteOne({ _id: ObjectId("5e775c47...") });
// Ví dụ xóa Chris trùng (giữ ObjectId("5e775c37..."))
db.demo438.deleteOne({ _id: ObjectId("5e775c40...") });

Cách tự động hóa (Script trong Shell):

db.demo438.aggregate([
    { $group: { _id: { FirstName: "$FirstName" }, ids: { $push: "$_id" }, count: { $sum: 1 } } },
    { $match: { count: { $gt: 1 } } }
]).forEach(doc => {
    doc.ids.slice(1).forEach(id => db.demo438.deleteOne({ _id: id })); // Giữ ids[0], xóa phần còn lại
});

MongoDB 4.2+ (Dễ hơn): Dùng deleteMany với $expr hoặc tạo unique index với dropDups: true (cẩn thận: dropDups xóa data ngẫu nhiên, đã deprecated).

Best Practice: Tạo **Unique Index** ngay từ đầu: db.demo438.createIndex({ FirstName: 1 }, { unique: true }) để ngăn chặn trùng lặp tại nguồn.