Computer >> บทช่วยสอนคอมพิวเตอร์ >  >> การเขียนโปรแกรม >> MongoDB

การลบข้อมูลซ้ำใน MongoDB 3.x ด้วย Aggregation $group และ $addToSet

หาเอกสารซ้ำ (Duplicate) ตามฟิลด์เฉพาะด้วย Aggregation

MongoDB 3.x ไม่มีคำสั่งลบซ้ำโดยตรง ใช้ Aggregation Pipeline หา _id ของเอกสารซ้ำ แล้วค่อยลบด้วยโค้ดเพิ่มเติม

ตัวอย่างข้อมูลทดสอบ (มี FirstName ซ้ำ)

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

แสดงข้อมูลทั้งหมด

> db.demo438.find();

ผลลัพธ์: 5 เอกสาร (Chris 2, David 2, Bob 1)

คำสั่ง Aggregation หา Duplicate Group

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

ผลลัพธ์ที่ได้ (กลุ่มตาม FirstName พร้อม _id ทั้งหมดในกลุ่ม)

{ "_id": { "FirstName": "David" }, "DuplicateValueIds": [ ObjectId("..."), ObjectId("...") ] }
{ "_id": { "FirstName": "Bob" }, "DuplicateValueIds": [ ObjectId("...") ] }
{ "_id": { "FirstName": "Chris" }, "DuplicateValueIds": [ ObjectId("..."), ObjectId("...") ] }

คำอธิบาย

  • $group: { _id: { FirstName: "$FirstName" }, ... }: จัดกลุ่มตามค่า FirstName
  • $addToSet: "$_id": สะสม _id ของทุกเอกสารในกลุ่มเป็นอาร์เรย์ (Unique)
  • กลุ่มที่มี DuplicateValueIds.length > 1 = มีข้อมูลซ้ำ

วิธีลบข้อมูลซ้ำ (เก็บตัวแรก ลบตัวหลัง)

รัน Aggregation แล้ววนลูปลบใน Application Code:

var duplicates = db.demo438.aggregate([
  { $group: { _id: { FirstName: "$FirstName" }, ids: { $addToSet: "$_id" }, count: { $sum: 1 } } },
  { $match: { count: { $gt: 1 } } }
]);

duplicates.forEach(function(group) {
  // เก็บตัวแรก (ids[0]) ลบตัวที่เหลือ (ids.slice(1))
  group.ids.slice(1).forEach(function(id) {
    db.demo438.deleteOne({ _id: id });
  });
});

วิธีทันสมัยกว่า (MongoDB 4.2+): ใช้ $merge หรือ $out

> db.demo438.aggregate([
  { $sort: { _id: 1 } },
  { $group: { _id: "$FirstName", doc: { $first: "$$ROOT" } } },
  { $replaceRoot: { newRoot: "$doc" } },
  { $merge: { into: "demo438_dedup", on: "_id", whenMatched: "replace", whenNotMatched: "insert" } }
]);

สร้างคอลเลกชันใหม่ที่ไม่มีข้อมูลซ้ำ

สร้าง Unique Index ป้องกันข้อมูลซ้ำในอนาคต

> db.demo438.createIndex({ FirstName: 1 }, { unique: true });

จะป้องกัน Insert ซ้ำได้ (Throw Duplicate Key Error)