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

ลบข้อมูลซ้ำ (Duplicate) โดยอ้างอิง 2 Keys ใน MongoDB

การลบเอกสารซ้ำที่มีค่า field เดียวกัน 2 fields (Composite Key) ทำได้ด้วย aggregate pipeline ใช้ $group จัดกลุ่ม $first เก็บเอกสารแรก แล้ว $out เขียนทับคอลเลกชันเดิม

สร้างคอลเลกชันและข้อมูลตัวอย่าง (มีข้อมูลซ้ำ)

> db.demo108.insertOne({"Value1":23,"Value2":24});
{ "acknowledged" : true, "insertedId" : ObjectId("5e2ee3e49fd5fd66da214477") }
> db.demo108.insertOne({"Value1":23,"Value2":25});
{ "acknowledged" : true, "insertedId" : ObjectId("5e2ee3f29fd5fd66da214478") }
> db.demo108.insertOne({"Value1":23,"Value2":24});  // ซ้ำกับตัวแรก
{ "acknowledged" : true, "insertedId" : ObjectId("5e2ee3f59fd5fd66da214479") }

แสดงข้อมูลก่อนลบซ้ำ

> db.demo108.find();

ผลลัพธ์ (3 เอกสาร มีคู่ Value1=23, Value2=4 ซ้ำ 2 รายการ):

{ "_id" : ObjectId("5e2ee3e49fd5fd66da214477"), "Value1" : 23, "Value2" : 24 }
{ "_id" : ObjectId("5e2ee3f29fd5fd66da214478"), "Value1" : 23, "Value2" : 25 }
{ "_id" : ObjectId("5e2ee3f59fd5fd66da214479"), "Value1" : 23, "Value2" : 24 }

Query ลบข้อมูลซ้ำด้วย Aggregate + $out

> db.demo108.aggregate([
  { "$sort": { "_id": 1 } },
  {
    "$group": {
      "_id": { "Value1": "$Value1", "Value2": "$Value2" },
      "doc": { "$first": "$$ROOT" }
    }
  },
  { "$replaceRoot": { "newRoot": "$doc" } },
  { "$out": "demo108" }
]);

คำอธิบายขั้นตอน:

  1. $sort: {_id: 1}: เรียงตาม _id เก่าไปใหม่ (เก็บตัวแรกที่ insert)
  2. $group: จัดกลุ่มตาม composite key (Value1, Value2) เก็บเอกสารแรก ($first) ของแต่ละกลุ่ม
  3. $replaceRoot: นำ doc ที่เก็บไว้ มาเป็น root document ใหม่
  4. $out: "demo108": เขียนผลลัพธ์ทับคอลเลกชันเดิม (แทนที่ข้อมูลทั้งหมด)

ผลลัพธ์หลังลบซ้ำ

> db.demo108.find();

ผลลัพธ์ (เหลือ 2 เอกสาร ไม่ซ้ำ):

{ "_id" : ObjectId("5e2ee3f29fd5fd66da214478"), "Value1" : 23, "Value2" : 25 }
{ "_id" : ObjectId("5e2ee3e49fd5fd66da214477"), "Value1" : 23, "Value2" : 24 }

วิธีอื่น: สร้าง Unique Index (ป้องกันล่วงหน้า)

db.demo108.createIndex({Value1: 1, Value2: 1}, {unique: true})

จะป้องกันการ insert ซ้ำในอนาคต แต่ต้องลบข้อมูลซ้ำเดิมก่อนสร้าง index

ลบซ้ำโดยเก็บ _id ใหม่ (ไม่เก็บ _id เดิม)

db.demo108.aggregate([
  { $group: { _id: {Value1: "$Value1", Value2: "$Value2"}, doc: { $first: "$$ROOT" }}},
  { $replaceRoot: { newRoot: "$doc" }},
  { $project: { _id: 0 }},  // ลบ _id เดิม
  { $out: "demo108" }
])

ข้อควรระวัง: $out จะลบคอลเลกชันเดิมและสร้างใหม่ - index ทั้งหมดจะหายไป ต้องสร้าง index ใหม่หลังรัน