MongoDB เป็นฐานข้อมูลแบบ NoSQL ที่จัดเก็บข้อมูลในรูปแบบ Document โดยใช้โครงสร้างคล้าย JSON และจัดเก็บจริงในรูปแบบ BSON จุดเด่นคือความยืดหยุ่นของโครงสร้างข้อมูล การรองรับข้อมูลที่เปลี่ยนแปลงได้ และการเขียน Query ที่เหมาะกับรูปแบบข้อมูลของแอปพลิเคชัน

บทความนี้อธิบายแนวคิดสำคัญของ MongoDB ตั้งแต่โครงสร้างพื้นฐาน การทำ CRUD การออกแบบข้อมูล การสร้าง Index การใช้ Aggregation ไปจนถึงตัวอย่างการเชื่อมต่อกับ Backend

#1. MongoDB คืออะไร

MongoDB เป็นฐานข้อมูลแบบ Document-Oriented Database ซึ่งข้อมูลถูกจัดเก็บเป็นเอกสารใน Collection แทนการจัดเก็บเป็นแถวและคอลัมน์แบบฐานข้อมูลเชิงสัมพันธ์

ตัวอย่างเอกสารผู้ใช้งาน:

{
  "_id": "u1001",
  "name": "Naruapon",
  "email": "naruapon@example.com",
  "roles": ["instructor", "researcher"],
  "profile": {
    "department": "Software Engineering",
    "organization": "NPRU"
  },
  "createdAt": "2026-10-18T00:00:00Z"
}

เอกสารหนึ่งรายการสามารถมี Object ซ้อนกันและ Array ได้ จึงเหมาะกับข้อมูลที่มีโครงสร้างใกล้เคียงกับ Object ในโปรแกรม

#2. โครงสร้างข้อมูลของ MongoDB

MongoDB แนวคิดที่ใกล้เคียงใน SQL
Database Database
Collection Table
Document Row
Field Column
Embedded Document ข้อมูลที่ฝังอยู่ภายใน Row
Array กลุ่มค่าหรือรายการย่อย

ตัวอย่างลำดับโครงสร้าง:

MongoDB Server
└── Database: university
    └── Collection: lecturers
        └── Document
            ├── name
            ├── email
            └── researchAreas[]

MongoDB ไม่ได้บังคับให้ทุก Document ใน Collection ต้องมี Field เหมือนกันทั้งหมด แต่ในระบบจริงควรออกแบบ Schema ให้มีมาตรฐาน เพื่อให้ Query การตรวจสอบข้อมูล และการดูแลระบบทำได้ง่าย

#3. จุดเด่นและข้อควรระวัง

#จุดเด่น

  • เก็บข้อมูลแบบ Nested Object และ Array ได้โดยตรง
  • เหมาะกับข้อมูลที่มีโครงสร้างเปลี่ยนแปลงบ่อย
  • Query และ Aggregation มีความยืดหยุ่น
  • ขยายระบบด้วย Replication และ Sharding ได้
  • มี Driver สำหรับหลายภาษา เช่น JavaScript, Java, Python, Go, C# และ PHP
  • เหมาะกับระบบ Web API, Event Data, Catalog, Content และระบบที่ต้องพัฒนาเร็ว

#ข้อควรระวัง

  • Flexible Schema ไม่ได้หมายความว่าไม่ต้องออกแบบข้อมูล
  • การฝังข้อมูลมากเกินไปอาจทำให้ Document ใหญ่และแก้ไขยาก
  • Index ช่วยให้การอ่านเร็วขึ้น แต่เพิ่มต้นทุนในการเขียนและใช้พื้นที่
  • ความสัมพันธ์ที่ซับซ้อนมากอาจเหมาะกับการอ้างอิงหรือฐานข้อมูลเชิงสัมพันธ์มากกว่า
  • ควรวางแผนเรื่องสิทธิ์ การสำรองข้อมูล และการตรวจสอบ Schema ตั้งแต่เริ่มต้น

#4. การติดตั้ง MongoDB ด้วย Docker Compose

ตัวอย่างไฟล์ compose.yaml สำหรับการทดลองในเครื่อง:

services:
  mongodb:
    image: mongo:8
    container_name: mongodb-dev
    restart: unless-stopped
    ports:
      - "27017:27017"
    environment:
      MONGO_INITDB_ROOT_USERNAME: admin
      MONGO_INITDB_ROOT_PASSWORD: change-me
    volumes:
      - mongodb_data:/data/db

volumes:
  mongodb_data:

คำสั่งเริ่มต้นระบบ:

docker compose up -d
docker compose ps

คำสั่งเชื่อมต่อด้วย mongosh:

mongosh "mongodb://admin:change-me@localhost:27017/?authSource=admin"

สำหรับ Production ควรใช้ Secret หรือระบบจัดการความลับแทนการเขียนรหัสผ่านไว้ในไฟล์โดยตรง

#5. การใช้งาน MongoDB Shell

เลือก Database ที่ต้องการใช้งาน:

use university

สร้างข้อมูลหนึ่งรายการ:

db.lecturers.insertOne({
  name: "Naruapon Suwanwijit",
  email: "naruapon@example.com",
  department: "Software Engineering",
  researchAreas: ["Software Testing", "AI Agents", "RAG"],
  active: true
})

สร้างหลายรายการ:

db.lecturers.insertMany([
  {
    name: "Kanchana Viriyapant",
    department: "Computer Science",
    active: true
  },
  {
    name: "Nalinpat Bhumpenpien",
    department: "Information Technology",
    active: true
  }
])

#6. CRUD Operations

CRUD ประกอบด้วย Create, Read, Update และ Delete

#Create

db.students.insertOne({
  studentId: "S001",
  name: "Somchai",
  program: "Software Engineering",
  gpa: 3.45
})

#Read

อ่านข้อมูลทั้งหมด:

db.students.find()

ค้นหาด้วยเงื่อนไข:

db.students.find({
  program: "Software Engineering",
  gpa: { $gte: 3.00 }
})

เลือกเฉพาะ Field ที่ต้องการ:

db.students.find(
  { gpa: { $gte: 3.00 } },
  { _id: 0, studentId: 1, name: 1, gpa: 1 }
)

#Update

db.students.updateOne(
  { studentId: "S001" },
  {
    $set: { gpa: 3.60 },
    $currentDate: { updatedAt: true }
  }
)

เพิ่มสมาชิกใน Array โดยไม่เพิ่มค่าซ้ำ:

db.students.updateOne(
  { studentId: "S001" },
  { $addToSet: { skills: "MongoDB" } }
)

#Delete

db.students.deleteOne({ studentId: "S001" })

ควรใช้ Filter ที่ชัดเจนเสมอ และตรวจสอบผลลัพธ์ก่อนใช้ deleteMany() ในระบบจริง

#7. การออกแบบข้อมูล: Embed หรือ Reference

#Embed: ฝังข้อมูลไว้ใน Document เดียวกัน

เหมาะเมื่อข้อมูลถูกใช้งานร่วมกันบ่อย มีขนาดไม่ใหญ่ และต้องการอ่านด้วย Query เดียว

{
  "orderNo": "ORD-1001",
  "customer": {
    "name": "Somchai",
    "email": "somchai@example.com"
  },
  "items": [
    { "productId": "P01", "name": "Keyboard", "quantity": 1 },
    { "productId": "P02", "name": "Mouse", "quantity": 2 }
  ]
}

#Reference: เก็บรหัสอ้างอิงไปยัง Document อื่น

เหมาะเมื่อข้อมูลมีขนาดใหญ่ ถูกใช้งานร่วมกันหลายส่วน หรือมีการเปลี่ยนแปลงแยกจากกันบ่อย

{
  "orderNo": "ORD-1001",
  "customerId": "C001",
  "items": [
    { "productId": "P01", "quantity": 1 }
  ]
}

หลักสำคัญคือออกแบบตาม Query ที่ระบบต้องใช้จริง ไม่ควรแปลงตารางจาก SQL เป็น Collection แบบหนึ่งต่อหนึ่งโดยไม่พิจารณารูปแบบการอ่านข้อมูล

#8. Index และประสิทธิภาพ

สร้าง Index สำหรับ Field ที่ใช้ค้นหา เรียงลำดับ หรือกรองข้อมูลบ่อย:

db.students.createIndex({ studentId: 1 }, { unique: true })
db.students.createIndex({ program: 1, gpa: -1 })

ตรวจสอบแผนการทำงานของ Query:

db.students
  .find({ program: "Software Engineering" })
  .explain("executionStats")

แนวทางที่ควรทำ:

  1. เริ่มจาก Query ที่ระบบใช้งานจริง
  2. สร้าง Index ให้ตรงกับ Filter และ Sort
  3. ตรวจสอบด้วย explain()
  4. ติดตาม Index ที่ไม่ได้ใช้งาน
  5. หลีกเลี่ยงการสร้าง Index จำนวนมากโดยไม่มีเหตุผล

#9. Aggregation Pipeline

Aggregation Pipeline คือกระบวนการนำ Document ผ่านหลาย Stage เพื่อกรอง จัดกลุ่ม เรียงลำดับ และคำนวณผลลัพธ์

ตัวอย่างหาค่าเฉลี่ย GPA แยกตามหลักสูตร:

db.students.aggregate([
  {
    $match: { active: true }
  },
  {
    $group: {
      _id: "$program",
      averageGpa: { $avg: "$gpa" },
      totalStudents: { $sum: 1 }
    }
  },
  {
    $sort: { averageGpa: -1 }
  }
])

Stage ที่พบได้บ่อย:

Stage หน้าที่
$match กรอง Document
$project เลือกหรือคำนวณ Field
$group จัดกลุ่มและสรุปผล
$sort เรียงลำดับ
$limit จำกัดจำนวนผลลัพธ์
$lookup เชื่อมข้อมูลจาก Collection อื่น
$unwind แยกสมาชิกใน Array ออกเป็นหลาย Document

ควรใช้ $match ในช่วงต้นของ Pipeline เมื่อทำได้ เพื่อให้ข้อมูลที่ต้องประมวลผลลดลง

#10. ตัวอย่างเชื่อมต่อด้วย Node.js

ติดตั้ง MongoDB Driver:

npm install mongodb

ตัวอย่างการเชื่อมต่อ:

import { MongoClient } from "mongodb";

const uri = process.env.MONGODB_URI;
const client = new MongoClient(uri);

async function main() {
  await client.connect();

  const db = client.db("university");
  const lecturers = db.collection("lecturers");

  await lecturers.insertOne({
    name: "Naruapon",
    department: "Software Engineering",
    active: true
  });

  const result = await lecturers
    .find({ active: true })
    .sort({ name: 1 })
    .toArray();

  console.log(result);
  await client.close();
}

main().catch(console.error);

ใน Production ควรจัดการ Connection Pool ให้เหมาะสม ไม่เปิด Connection ใหม่ทุก Request และควรเก็บ Connection String ไว้ใน Environment Variable

#11. ความปลอดภัยและการดูแลระบบ

  • เปิด Authentication และกำหนด Role ตามหลัก Least Privilege
  • ไม่เปิด Port ของฐานข้อมูลสู่สาธารณะโดยไม่จำเป็น
  • ใช้ TLS สำหรับการเชื่อมต่อที่ผ่านเครือข่ายที่ไม่ปลอดภัย
  • แยกฐานข้อมูล Development, Staging และ Production
  • กำหนด Backup และทดสอบการ Restore เป็นระยะ
  • ตรวจสอบ Slow Query, Error Log และการใช้ทรัพยากร
  • ใช้ Schema Validation เมื่อข้อมูลมีรูปแบบที่ต้องควบคุม
  • หลีกเลี่ยงการเก็บรหัสผ่านแบบ Plain Text

ตัวอย่าง Schema Validation แบบง่าย:

db.createCollection("students", {
  validator: {
    $jsonSchema: {
      bsonType: "object",
      required: ["studentId", "name", "gpa"],
      properties: {
        studentId: { bsonType: "string" },
        name: { bsonType: "string" },
        gpa: { bsonType: "double", minimum: 0, maximum: 4 }
      }
    }
  }
})

#12. MongoDB เหมาะกับงานแบบใด

MongoDB เหมาะกับระบบที่มีข้อมูลเป็นเอกสารหรือข้อมูลกึ่งโครงสร้าง เช่น

  • REST API และ Backend ของ Web Application
  • Product Catalog ที่แต่ละสินค้าอาจมี Attribute ไม่เหมือนกัน
  • ระบบ Content และบทความ
  • Event และ Log Data
  • ระบบที่ต้องพัฒนา Schema อย่างต่อเนื่อง
  • ระบบ Real-time ที่ใช้ Change Streams
  • ระบบค้นหาและวิเคราะห์ข้อมูลเอกสาร

MongoDB อาจไม่ใช่ตัวเลือกแรกเมื่อระบบมี Transaction ซับซ้อนมาก ความสัมพันธ์ระหว่างข้อมูลมีจำนวนมาก หรือรายงานต้องใช้ Join เชิงตารางเป็นหลัก แม้ MongoDB จะมี Transaction และ $lookup รองรับก็ตาม

#13. สรุปแนวคิดสำคัญ

  1. MongoDB จัดเก็บข้อมูลเป็น Document ใน Collection
  2. Document รองรับ Object ซ้อนและ Array ทำให้ใกล้เคียงกับโครงสร้างข้อมูลในโปรแกรม
  3. Flexible Schema ต้องใช้ร่วมกับมาตรฐานข้อมูลและ Validation ที่เหมาะสม
  4. ออกแบบข้อมูลตาม Query และรูปแบบการใช้งานจริง
  5. ใช้ Index กับ Query ที่สำคัญ และตรวจสอบด้วย explain()
  6. ใช้ Aggregation Pipeline สำหรับการกรอง จัดกลุ่ม และคำนวณข้อมูล
  7. Production ต้องให้ความสำคัญกับ Authentication, Backup, Monitoring และการจำกัดสิทธิ์

#แหล่งอ้างอิง