ข้ามไปยังเนื้อหา

การ insert document

การ insert คือ operation ที่ผ่อนคลายที่สุดใน MongoDB คุณยื่น document ให้ฐานข้อมูล ฐานข้อมูลเก็บไว้ แล้วตอบกลับมาว่าเก็บอะไรไป ไม่ต้องนิยาม schema ล่วงหน้า ไม่มีคอลัมน์ของตารางให้จัดให้ตรงกัน — ขอแค่ document เป็นข้อมูลคล้าย JSON ที่ถูกต้องก็เข้าได้เลย

อิสระตรงนี้แหละคือเหตุผลว่าทำไมวินัยเล็ก ๆ รอบ field _id ถึงคุ้มค่า เพราะเป็นงานเก็บบันทึกชิ้นเดียวที่ทุกการ insert ต้องยุ่งด้วย

เราจะสร้างห้องสมุดสมมติกันต่อ สมาชิกแต่ละคนคือ document หนึ่งรายการ และบทเรียนนี้เราจะเพิ่มสมาชิกเข้าไปใน collection ชื่อ members

insertOne รับ document มาหนึ่งรายการพอดีแล้วเก็บลง collection ถ้าคุณไม่ได้ระบุ _id มาเอง MongoDB จะสร้างให้ในรูปของ ObjectId — ค่าขนาด 12 ไบต์ที่ไม่ซ้ำกันทั่วทั้ง collection และเข้ารหัสเวลาที่สร้างเอาไว้ในตัว ตัว id ที่ได้นี้แหละคือ primary key ของ document

db.members.insertOne({ name: "Grace", joined: 2024, fines: 0 })

acknowledgement บอกว่า operation สำเร็จ พร้อมส่ง id ที่กำหนดให้กลับมาด้วย ในเชลล์จะหน้าตาแบบนี้:

{ "acknowledged": true, "insertedId": "65f0b3d4e4b0a1c2e4b0a1d0" }

ส่วน document ที่นอนอยู่ใน collection ตอนนี้หน้าตาแบบนี้ — _id คือสิ่งเดียวที่คุณไม่ได้พิมพ์เอง:

{
"_id": "65f0b3d4e4b0a1c2e4b0a1d0",
"name": "Grace",
"joined": 2024,
"fines": 0
}

ใน Compass: เปิด collection members คลิกปุ่มสีเขียว ADD DATA เลือก Insert Document วาง JSON ลงไปโดยไม่ต้องใส่ _id แล้ว Compass จะเติม id ให้เองตอนกดบันทึก

เมื่อมี document เป็นชุด insertMany ส่งทั้งชุดไปใน round trip เดียว แทนที่จะเรียกทีละครั้งต่อหนึ่ง document คุณส่ง array เข้าไป แล้วได้ id ของทุกรายการที่ insert สำเร็จกลับมา โดยใช้ตำแหน่งใน array เป็น key

db.members.insertMany([
{ name: "Linus", joined: 2023, fines: 2 },
{ name: "Margaret", joined: 2025, fines: 0 },
{ name: "Edsger", joined: 2022, fines: 5 }
])

acknowledgement จับคู่ index ของแต่ละรายการใน array เข้ากับ id ที่สร้างให้:

{
"acknowledged": true,
"insertedIds": {
"0": "65f0b3d4e4b0a1c2e4b0a1d1",
"1": "65f0b3d4e4b0a1c2e4b0a1d2",
"2": "65f0b3d4e4b0a1c2e4b0a1d3"
}
}
  • คุณกำหนด _id เองได้ (เป็น string, number หรือค่าอะไรก็ได้) แทนการปล่อยให้ MongoDB สร้าง ObjectId — แต่ค่าต้องไม่ซ้ำ ถ้า insert document ที่ _id มีอยู่แล้ว จะล้มเหลวพร้อม error แบบ duplicate key
  • insertMany เป็นแบบ ordered โดยปริยาย คือหยุดทันทีที่ document ตัวแรกล้มเหลว ตัวที่อยู่ถัดจาก error เรื่อง id ซ้ำจึงไม่ได้เข้า collection เลย ถ้าอยากให้ไปต่อแม้เจอตัวที่ล้มเหลว แล้ว insert ทุกตัวที่ไม่ชนกัน ให้ส่ง option แบบ unordered เข้าไป
  • ไม่มี schema มาบังคับ ทำให้ document สองรายการใน collection เดียวกันมี field ต่างกันคนละเรื่องได้ การ insert ใจดีแบบนี้ถือเป็นฟีเจอร์ ไม่ใช่บั๊ก — แต่คุณต้องตั้งใจรักษาความสม่ำเสมอเอง
ตัวเลือกBenefitCost
insertOneเรียบง่าย จัดการ error ของแต่ละ document ตรงไปตรงมาหนึ่ง round trip ต่อหนึ่ง document ช้าเมื่อมีจำนวนมาก
insertMany (ordered)batch เดียว ลด round tripdocument ตัวแรกที่ error หยุดทั้งชุด ตัวที่เหลือไม่ได้เข้า
insertMany (unordered)ไปต่อแม้เจอ document ที่ error แล้ว insert ทุกตัวที่ไม่ชนกันลำดับการ insert ไม่การันตี ต้องแกะผลลัพธ์เพื่อรู้ว่าตัวไหนล้มเหลว
  • insert document ทีละตัวในลูปแทนที่จะใช้ insertMany — เสีย round trip โดยไม่จำเป็น ยิ่งจำนวน document เยอะยิ่งช้าเห็นได้ชัด ควรรวมเป็น array แล้วเรียก insertMany ครั้งเดียว
  • คิดว่า insertOne คืน document ที่ insert ไปกลับมาเต็ม ๆ — จริง ๆ คืนแค่ acknowledgement กับ insertedId เท่านั้น ถ้าอยากได้ document เต็ม ต้อง findOne ด้วย _id นั้นอีกที
  • ไม่ตรวจ insertedCount ของ insertMany แบบ unordered — เข้าใจว่า “ไม่มี error โยนขึ้นมา” แปลว่า document ทุกตัวถูก insert ครบ ทั้งที่ unordered อาจข้าม document ที่ล้มเหลวไปเงียบ ๆ ต้องเทียบ insertedCount กับจำนวนที่ส่งเข้าไป

💡 ตัวอย่างจากของจริง

ระบบ import สินค้าเข้าคลัง (e-commerce) — เมื่อ merchant อัปโหลดไฟล์ CSV สินค้าหลายพันรายการ ระบบแปลงแต่ละแถวเป็น document แล้วส่งเข้า insertMany เป็นชุด (batch) ละ 500 รายการ แทนที่จะ insertOne ทีละแถว

ระบบ log/event ingestion — service ที่รับ event จำนวนมากต่อวินาที มักสะสม event ไว้ใน buffer สั้น ๆ แล้ว insertMany แบบ unordered เป็นก้อนเดียว เพื่อไม่ให้ event หนึ่งตัวที่ผิดรูปแบบไปบล็อก event อื่นทั้งหมด

ถ้าคุณ insert document โดยไม่มี field _id จะเกิดอะไรขึ้น?
โดยปริยาย insertMany แบบ ordered ทำอย่างไรเมื่อ document หนึ่งมี _id ซ้ำ?
acknowledgement ของ insertMany มีอะไรอยู่ในนั้น?