Back

พื้นฐาน NoSQL Database และ MongoDBBlur image

บทความนี้คือจุดเริ่มต้นสำหรับผู้ที่อยากเข้าใจ NoSQL Database ตั้งแต่แนวคิด รูปแบบข้อมูล JSON ประเภทของ NoSQL ไปจนถึงการใช้งาน MongoDB ซึ่งเป็น NoSQL ยอดนิยมที่เก็บข้อมูลเป็นเอกสาร (Document) พร้อมตัวอย่างคำสั่งตั้งแต่สร้าง เพิ่ม ค้น แก้ไข ลบ ไปจนถึง Aggregation และมี แบบฝึกหัด ท้ายแต่ละหัวข้อ

1. NoSQL คืออะไร#

NoSQL (ย่อมาจาก “Not Only SQL”) คือกลุ่มของระบบจัดการฐานข้อมูลที่ออกแบบมาเพื่อรองรับการทำงานที่ Relational Database (RDBMS) แบบดั้งเดิมตอบโต้ได้ยาก เช่น ข้อมูลปริมาณมหาศาล โครงสร้างข้อมูลที่เปลี่ยนแปลงบ่อย และการขยายตัวแบบกระจาย (horizontal scaling)

จุดเด่นของ NoSQL คือ Schema ยืดหยุ่น — ไม่ต้องกำหนดโครงสร้างตารางที่ตายตัวล่วงหน้า แต่ละระเบียน (record) สามารถมีฟิลด์ที่ต่างกันได้ ทำให้เพิ่มฟิลด์ใหม่ได้โดยไม่ต้อง ALTER TABLE และเก็บข้อมูลที่ซ้อนกัน (nested) หรือเป็นกลุ่มไม่จำกัดได้ตามธรรมชาติ

NoSQL Overview

NoSQL เกิดขึ้นเพื่อตอบโจทย์ 4 ด้านหลัก ได้แก่

ปริมาณข้อมูลมหาศาล (Big Data)#

NoSQL ออกแบบมาให้กระจายข้อมูลข้ามเซิร์ฟเวอร์หลายเครื่องได้ (sharding) ยิ่งข้อมูลเพิ่มขึ้น ก็เพิ่มเซิร์ฟเวอร์เข้าไปได้เรื่อย ๆ แทนที่จะต้องซื้อเครื่องเดียวที่แพงและทรงพลังมากขึ้นเรื่อย ๆ แบบ RDBMS แบบเดิม

โครงสร้างข้อมูลเปลี่ยนแปลงบ่อย (Flexible Schema)#

ในแอปพลิเคชันสมัยใหม่ โครงสร้างข้อมูลมักเปลี่ยนไปตามการพัฒนา NoSQL ให้เพิ่มหรือเปลี่ยนฟิลด์ได้โดยไม่ต้อง migrate ตารางทั้งตาราง เหมาะกับ rapid prototyping และข้อมูลที่หลากหลาย

ความเร็วสูง (Performance)#

NoSQL หลายประเภทเสียสละความสามารถบางอย่างของ RDBMS (เช่น JOIN ที่ซับซ้อน, transaction แบบเข้มข้น) เพื่อแลกกับความเร็วในการอ่าน/เขียนที่สูงมาก เช่น Redis ที่เก็บข้อมูลใน memory

รูปแบบข้อมูลหลากหลาย (Variety)#

NoSQL รองรับข้อมูลหลายรูปแบบ โดยแบ่งเป็น 4 ประเภทหลัก แต่ละประเภทเก็บข้อมูลคนละแบบ เหมาะกับงานคนละแบบ:

  • Document — เก็บข้อมูลเป็นเอกสารคล้าย JSON ที่ซ้อนกันได้ และแต่ละเอกสารมีฟิลด์ต่างกันได้ เหมาะกับข้อมูลเอกสาร/catalog (เช่น MongoDB)
  • Key-Value — เก็บเป็นคู่คีย์-ค่าเรียบง่าย อ่าน/เขียนเร็วมาก เหมาะกับ cache, session (เช่น Redis)
  • Wide Column — เก็บเป็นตารางที่แต่ละแถวมีคอลัมน์ต่างกันได้ รองรับข้อมูลปริมาณมหาศาล เหมาะกับ time-series, log (เช่น Cassandra)
  • Graph — เก็บเป็นโหนด (node) และความสัมพันธ์ (edge) เน้นความสัมพันธ์ระหว่างข้อมูล เหมาะกับ social network, ระบบแนะนำ (เช่น Neo4j)

การเลือกประเภทให้ตรงกับลักษณะของข้อมูลเป็นหัวใจสำคัญ — รายละเอียดเปรียบเทียบแบบเต็มจะอธิบายในหัวข้อประเภทของ NoSQL

สรุป: NoSQL ไม่ได้มาแทน RDBMS แต่มาเสริม — เลือกใช้ตามลักษณะงาน เช่น ข้อมูลเอกสาร/hierarchical เลือก Document DB, ข้อมูลแคชเร็วเลือก Key-Value

📝 แบบฝึกหัด

  1. จงอธิบายด้วยคำพูดของคุณเองว่า ทำไม RDBMS อาจไม่เหมาะกับข้อมูลที่โครงสร้างเปลี่ยนแปลงบ่อย
  2. ยกตัวอย่าง แอปพลิเคชัน 1 อย่างที่คิดว่า NoSQL เหมาะกว่า RDBMS พร้อมเหตุผล

2. JSON คืออะไร#

ก่อนเข้าใจ Document Database อย่าง MongoDB ต้องเข้าใจ JSON เสียก่อน เพราะ MongoDB เก็บข้อมูลในรูปแบบที่คล้าย JSON มาก

JSON (JavaScript Object Notation) คือรูปแบบข้อความ (text) สำหรับจัดเก็บและแลกเปลี่ยนข้อมูล ที่ทั้งมนุษย์อ่านง่ายและเครื่องจัดประมวลผลได้สะดวก แม้ชื่อจะมีคำว่า JavaScript แต่ JSON เป็นรูปแบบอิสระ — ภาษาเกือบทุกภาษา (Python, Java, PHP, Go, ฯลฯ) อ่าน/เขียน JSON ได้

JSON Structure

โครงสร้างพื้นฐานของ JSON#

JSON ประกอบด้วย คู่คีย์-ค่า (key-value) เขียนอยู่ในเครื่องหมายปีกกา { } คีย์ต้องเป็นข้อความที่อยู่ในเครื่องหมายคำพูดคู่ " " ส่วนค่าสามารถเป็นได้หลายชนิด

{
  "name": "Wireless Mouse",
  "price": 590,
  "inStock": true,
  "rating": 4.5,
  "tags": ["wireless", "ergonomic"],
  "specs": {
    "color": "black",
    "battery": "AAA"
  },
  "discount": null
}
json

💡 ทริค: แนะนำให้เขียน JSON ใน VS Code เพราะโปรแกรมจะช่วยเช็ค syntax ให้ทันที เช่น ลืมใส่จุลภาค , ใช้เครื่องหมายคำพูดผิดแบบ (เช่น single quote แทน double quote) หรือลืมปิดปีกกา — VS Code จะขีดเส้นแดงแจ้งเตือน ทำให้เขียน JSON ให้ถูกต้องได้ง่ายและเร็วขึ้นมาก (หากยังไม่มี ดาวน์โหลดได้ฟรีที่ code.visualstudio.com)

ชนิดข้อมูลใน JSON#

ชนิดตัวอย่างคำอธิบาย
String"Wireless Mouse"ข้อความ ใส่ในเครื่องหมายคำพูดคู่เสมอ
Number590, 4.5ตัวเลข (ทั้งจำนวนเต็มและทศนิยม)
Booleantrue, falseค่าจริง/เท็จ (ไม่ใส่เครื่องหมายคำพูด)
Nullnullค่าว่าง (ไม่ใส่เครื่องหมายคำพูด)
Array["wireless", "ergonomic"]ลำดับของค่า อยู่ใน [ ]
Object{ "color": "black" }คู่คีย์-ค่า อยู่ใน { } (ซ้อนกันได้)

จุดที่ทำให้ JSON ทรงพลังคือ Object และ Array สามารถซ้อนกันได้ลึกไม่จำกัด เช่น specs เป็น object ที่ซ้อนใน object ใหญ่ หรือ tags เป็น array ของข้อความ คุณสมบัตินี้ทำให้ JSON เก็บข้อมูลที่มีโครงสร้างซับซ้อน (hierarchical) ได้อย่างเป็นธรรมชาติ

ทำไม JSON จึงสำคัญ#

  • แลกเปลี่ยนข้อมูลระหว่างระบบ — REST API ส่ง/รับข้อมูลเป็น JSON เกือบทั้งหมด
  • ไฟล์ตั้งค่า (config) — เช่น package.json, tsconfig.json
  • เป็นรากฐานของ Document Database — MongoDB เก็บแต่ละ record เป็นเอกสารรูปแบบ JSON (จริง ๆ คือ BSON ซึ่งเป็น JSON แบบ binary จะอธิบายในหัวข้อถัดไป)

เคล็ดลับ — ความผิดพลาดที่พบบ่อย: คีย์ของ JSON ต้องใส่เครื่องหมางคำพูดคู่เสมอ ("name" ไม่ใช่ name) และห้ามมี comma ต่อท้ายคู่สุดท้าย (trailing comma) มิฉะนั้นจะ parse ไม่ผ่าน

สรุป: JSON เป็นรูปแบบข้อความ key-value ที่มนุษย์และเครื่องอ่านได้ รองรับชนิดข้อมูล 6 แบบ และ object/array ซ้อนกันได้ จึงเป็นรากฐานของ document database และการแลกเปลี่ยนข้อมูลทุกวันนี้

📝 แบบฝึกหัด

  1. จงเขียน JSON ของสินค้า “Notebook” ราคา 35 หมวด Stationery มีแท็ก ["school", "office"] และมี inStock เป็นจริง
  2. JSON ต่อไปนี้มี 2 จุดที่ผิด จงแก้ให้ถูกต้อง: { name: 'Pen', price: 20, }
  3. ค่า 20 และ true ใน JSON เป็นชนิดข้อมูลใด? (จงตอบโดยไม่ใส่เครื่องหมายคำพูด)

3. SQL vs NoSQL — เลือกแบบไหน#

ทั้งสองแบบไม่ได้ดีกว่ากันอย่างเด็ดขาด แต่เหมาะกับงานต่างกัน

ด้านRelational (SQL)NoSQL
โครงสร้างตาราง (table) แถว/คอลัมน์ มี schema ตายตัวเอกสาร/คีย์-ค่า/คอลัมน์/กราฟ schema ยืดหยุ่น
ภาษาSQLขึ้นกับระบบ (MongoDB ใช้คำสั่งแบบ JavaScript)
ความสัมพันธ์JOIN ระหว่างตาราง, foreign keyมักฝังข้อมูลที่เกี่ยวข้องไว้ด้วยกัน (embed)
การขยายมักขยายเครื่องเดียวให้แรงขึ้น (vertical)กระจายข้ามหลายเครื่องได้ดี (horizontal)
Transactionแข็งแกร่ง (ACID)มีบ้างแต่มักเน้นความเร็ว/ปริมาณ
ตัวอย่างMySQL, PostgreSQL, OracleMongoDB, Redis, Cassandra
เหมาะกับข้อมูลมีโครงสร้างชัดเจน ความสัมพันธ์ซับซ้อน (banking, ERP)ข้อมูลหลากหลาย/ซ้อนกัน ปริมาณมาก เปลี่ยนบ่อย (content, IoT, real-time)

สรุป: เลือก SQL เมื่อข้อมูลมีโครงสร้างตายตัวและต้องการความสัมพันธ์/transaction ที่เข้มข้น เลือก NoSQL เมื่อต้องการความยืดหยุ่น ความเร็ว และรองรับข้อมูลปริมาณมหาศาล

📝 แบบฝึกหัด

  1. ระบบ ธนาคาร/บัญชีเงินฝาก ควรใช้ SQL หรือ NoSQL? เพราะอะไร?
  2. แอปเก็บ log การคลิกของผู้ใช้นับล้าน record ต่อวัน ควรใช้แบบไหน? เพราะอะไร?

4. ประเภทของ NoSQL Database#

NoSQL แบ่งเป็น 4 ประเภทหลัก ตามรูปแบบการจัดเก็บข้อมูล

NoSQL Types

ประเภทรูปแบบข้อมูลตัวอย่างเหมาะกับ
Documentเอกสารคล้าย JSONMongoDB, CouchDBข้อมูลเอกสาร/hierarchical, content, catalog
Key-Valueคู่คีย์-ค่าเรียบง่ายRedis, DynamoDBcache, session, counter ความเร็วสูง
Wide Columnตารางที่แต่ละแถวมีคอลัมน์ต่างกันได้Cassandra, HBaseข้อมูล time-series, log, ปริมาณมาก
Graphโหนตและความสัมพันธ์ (node & edge)Neo4j, ArangoDBsocial network, recommendation, fraud detection

ในบทความนี้เราจะเน้นที่ Document Database โดยใช้ MongoDB เพราะเป็น NoSQL ที่นิยมและเข้าใจง่ายที่สุด และเก็บข้อมูลในรูปแบบ JSON ซึ่งนักพัฒนาคุ้นเคย

สรุป: เลือกประเภทตามลักษณะข้อมูล — เอกสาร→Document, แคชเร็ว→Key-Value, ปริมาณมากตามเวลา→Wide Column, ความสัมพันธ์ซับซ้อน→Graph

📝 แบบฝึกหัด

จงจับคู่ งาน กับ ประเภท NoSQL ที่เหมาะสมที่สุด (Document / Key-Value / Wide Column / Graph)

  1. ระบบแนะนำเพื่อนบนโซเชียลเน็ตเวิร์ก
  2. เก็บ session ผู้ใช้ชั่วคราวที่ต้องอ่านเร็วมาก
  3. เก็บบทความบล็อกที่มีคอมเมนต์ซ้อนอยู่ข้างใน
  4. เก็บข้อมูลเซนเซอร์อุณหภูมิทุกนาทีนับล้านจุดต่อวัน

5. MongoDB คืออะไร#

MongoDB คือ Document Database ยอดนิยมที่เก็บข้อมูลเป็น เอกสาร (Document) ในรูปแบบคล้าย JSON จริง ๆ แล้ว MongoDB เก็บเป็น BSON (Binary JSON) ซึ่งเป็น JSON ในรูปแบบ binary ที่ทำให้ค้นหาและประมวลผลได้เร็วขึ้น และรองรับชนิดข้อมูลเพิ่มเติม เช่น Date, ObjectId

Vocabulary — เปรียบเทียบกับ RDBMS#

RDBMSMongoDBคำอธิบาย
DatabaseDatabaseคอนเทนเนอร์รวม (เหมือนกัน)
TableCollectionที่เก็บกลุ่มของเอกสาร
RowDocumentหนึ่งระเบียนข้อมูล (JSON-like)
ColumnFieldคู่คีย์-ค่าหนึ่งคู่ในเอกสาร
Primary Key_idระบุเอกสารให้ไม่ซ้ำ (สร้างอัตโนมัติ)
SELECT * FROM tabledb.collection.find()ดึงข้อมูล

RDBMS vs MongoDB

ข้อแตกต่างสำคัญ: ใน RDBMS ทุกแถวในตารางต้องมีคอลัมน์เหมือนกัน แต่ใน MongoDB แต่ละเอกสารใน collection เดียวกันสามารถมีฟิลด์ต่างกันได้ ทำให้เก็บข้อมูลที่หลากหลายได้โดยไม่ต้องเปลี่ยนแปลงโครงสร้าง

สรุป: MongoDB เก็บข้อมูลเป็นเอกสาร BSON ใน collection โดยเทียบได้กับ row ใน table ของ RDBMS แต่ยืดหยุ่นกว่าเพราะแต่ละเอกสารมีฟิลด์ต่างกันได้

📝 แบบฝึกหัด

  1. คำว่า table, row, column ใน RDBMS เทียบกับคำใดใน MongoDB?
  2. ใน RDBMS เราเขียน SELECT * FROM products จงเขียนคำสั่งเทียบเท่าใน MongoDB
  3. ทำไมจึงกล่าวว่า “แต่ละเอกสารใน collection เดียวกันมีฟิลด์ต่างกันได้” เป็นจุดเด่นของ MongoDB?

6. เครื่องมือ — MongoDB Community Server และ Compass#

ในบทความ RDBMS เราใช้ MongoDB Community Server (เวอร์ชันฟรี ใช้งานได้เต็มที่) แล้วใช้ MongoDB Compass เป็น GUI จัดการฐานข้อมูล คล้าย phpMyAdmin

ดาวน์โหลดและติดตั้ง MongoDB Community Server#

  1. เปิดหน้าดาวน์โหลด: https://www.mongodb.com/try/download/community
  2. เลือก เวอร์ชันล่าสุด, ระบบปฏิบัติการ (Windows / macOS / Linux) และ รูปแบบตัวติดตั้ง (เช่น .msi สำหรับ Windows, .tgz/.zip สำหรับ macOS/Linux)
  3. ดาวน์โหลดแล้วรันตัวติดตั้ง — ระหว่างติดตั้งบน Windows แนะนำให้เลือก “Install MongoDB as a Service” (รันเป็นบริการเริ่มต้นอัตโนมัติทุกครั้งที่เปิดเครื่อง) และติดตั้ง MongoDB Compass ไปพร้อมกันได้เลย

เมื่อติดตั้งเสร็จ MongoDB จะทำงานเป็น background service คอยรับการเชื่อมต่อที่ port 27017 (ค่าเริ่มต้น)

MongoDB Community Server

MongoDB Compass — GUI จัดการฐานข้อมูล#

MongoDB Compass เป็น GUI สำหรับจัดการฐานข้อมูลคล้าย phpMyAdmin (ติดตั้งไปพร้อม Community Server ได้ หรือดาวน์โหลดแยกจากเว็บ MongoDB) เปิด Compass แล้ววาง connection string นี้เพื่อเชื่อมต่อกับเซิร์ฟเวอร์บนเครื่องของคุณ:

mongodb://localhost:27017

จากนั้นจะเห็น database, collection และเอกสารในรูปแบบกราฟิก สามารถเพิ่ม แก้ไข ลบ และรัน query ได้ผ่าน GUI โดยไม่ต้องใช้ command line

MongoDB Compass

ตัวอย่างคำสั่งในหัวข้อต่อ ๆ ไป เขียนในรูปแบบ mongosh (MongoDB Shell) ซึ่งเป็น JavaScript รันคำสั่งได้ทั้งใน Compass หรือ terminal

MongoDB shell


7. Database, Collection, Document — สร้างและเพิ่มข้อมูล#

เราจะใช้ฐานข้อมูลร้านค้าชื่อ shop และ collection ชื่อ products สมมติเก็บสินค้าที่มีรายละเอียดซ้อนกัน (specs, tags) ซึ่งเป็นจุดเด่นของ document database

สร้าง database และเพิ่มเอกสารเดียว (insertOne)#

ใน mongosh ใช้คำสั่ง use เพื่อสลับไปยัง database (สร้างอัตโนมัติเมื่อเพิ่มข้อมูลครั้งแรก) แล้วใช้ insertOne เพื่อเพิ่มเอกสาร

use shop

db.products.insertOne({
  name: "Wireless Mouse",
  price: 590,
  category: "Accessories",
  stock: 25,
  rating: 4.5,
  tags: ["wireless", "ergonomic"],
  specs: { color: "black", battery: "AAA" }
})
javascript

Insert Document

สังเกตว่าเราไม่ต้องสร้างตารางหรือกำหนด schema ล่วงหน้า — เพิ่มเอกสารเข้าไปได้เลย MongoDB จะสร้าง _id (primary key) ให้อัตโนมัติหากไม่ระบุ ตรวจสอบผลลัพธ์ได้ตามรูป

MongoDB Compass DB

เพิ่มหลายเอกสาร (insertMany)#

db.products.insertMany([
  { name: "Mechanical Keyboard", price: 1890, category: "Accessories", stock: 12, rating: 4.8 },
  { name: "USB-C Hub", price: 750, category: "Accessories", stock: 0, rating: 4.2 },
  { name: "4K Monitor", price: 8500, category: "Displays", stock: 8, rating: 4.7 },
  { name: "Laptop Stand", price: 690, category: "Accessories", stock: 30, rating: 4.0 },
  { name: "Webcam HD", price: 1200, category: "Electronics", stock: 15, rating: 4.3 },
  { name: "Bluetooth Speaker", price: 1450, category: "Electronics", stock: 18, rating: 4.6 },
  { name: "Desk Lamp", price: 560, category: "Accessories", stock: 0, rating: 3.9 }
])
javascript

ข้อมูลตัวอย่างนี้จะใช้สำหรับตัวอย่าง query ในหัวข้อถัดไป — สังเกตว่าสินค้าบางตัว (เช่น Wireless Mouse ตัวแรก) มี tags และ specs ส่วนตัวอื่นไม่มี นี่คือความยืดหยุ่นของ schema ที่ RDBMS ทำได้ยาก

สรุป: use <db> เลือก database, db.<collection>.insertOne() / insertMany() เพิ่มเอกสาร MongoDB สร้าง _id ให้อัตโนมัติ และยอมรับเอกสารที่มีฟิลด์ต่างกันใน collection เดียวกัน

📝 แบบฝึกหัด

  1. จงเขียนคำสั่ง insertOne เพิ่มสินค้า “USB Cable” ราคา 199 หมวด Accessories stock 50 rating 4.1
  2. หากต้องการเพิ่มสินค้า 3 ชนิดในคำสั่งเดียว ต้องใช้ insertOne หรือ insertMany? เพราะอะไร?
  3. ถ้าไม่ระบุฟิลด์ _id เอง MongoDB จะทำอย่างไร?

8. find() — ดึงข้อมูล#

คำสั่ง find() ของ MongoDB เทียบเท่า SELECT ของ SQL ใช้ดึงเอกสารจาก collection

ดึงทุกเอกสาร#

db.products.find()
javascript

เทียบเท่า SELECT * FROM products ใน SQL เพิ่ม .pretty() ถ้ารันใน shell เก่าเพื่อให้ผลลัพธ์อ่านง่าย (mongosh ปัจจุบันจัดรูปแบบให้อัตโนมัติ)

find()

ดึงเฉพาะฟิลด์ที่ต้องการ (Projection)#

เหมือนการเลือกคอลัมน์ใน SQL กำหนด 1 สำหรับฟิลด์ที่ต้องการแสดง และ 0 สำหรับฟิลด์ที่ต้องการซ่อน

// แสดงเฉพาะ name และ price (ซ่อน _id)
db.products.find({}, { name: 1, price: 1, _id: 0 })
javascript

ผลลัพธ์:

nameprice
Wireless Mouse590
Mechanical Keyboard1890
USB-C Hub750
4K Monitor8500
Laptop Stand690
Webcam HD1200
Bluetooth Speaker1450
Desk Lamp560

เคล็ดลับ: _id ถูกส่งกลับมาเสมอ หากไม่ต้องการให้ระบุ _id: 0 อย่างชัดเจน

💡 ใช้ผ่าน UI ก็ได้: นอกจากพิมพ์คำสั่งใน mongosh (MongoDB Shell) แล้ว คุณยังสามารถรัน find ผ่าน MongoDB Compass ซึ่งเป็น GUI ได้เช่นกัน ใน Compass มีช่องกรอก 2 ช่องที่ตรงกับอาร์กิวเมนต์ 2 ตัวของ find() คือ

  • Filter — ใส่เงื่อนไขกรอง (อาร์กิวเมนต์แรก) ที่นี่คือ {} หมายถึงไม่กรอง เอาทุกเอกสาร
  • Project — ใส่ projection ที่จะเลือกฟิลด์ (อาร์กิวเมนต์ที่สอง) ที่นี่คือ { name: 1, price: 1, _id: 0 }

กรอกเสร็จแล้วกดปุ่ม Find ผลลัพธ์จะแสดงเป็นตารางที่อ่านง่าย ด้านล่างคือการกรอกคำสั่ง db.products.find({}, { name: 1, price: 1, _id: 0 }) ผ่าน Compass — สังเกตว่าเราต้องใส่ { name: 1, price: 1, _id: 0 } ลงในช่อง Project เพื่อให้แสดงเฉพาะฟิลด์ name และ price และซ่อน _id

find projection in Compass

📝 แบบฝึกหัด

  1. จงเขียน find ที่ดึงเฉพาะฟิลด์ name และ rating จากทุกสินค้า (ซ่อน _id)
  2. คำสั่ง db.products.find({}) จะคืนผลลัพธ์เท่ากับคำสั่ง SQL ใด?
  3. จะซ่อนฟิลด์ _id ออกจากผลลัพธ์ต้องกำหนดค่าอะไรในส่วน projection?

9. Query Operators — กรองข้อมูลด้วยเงื่อนไข#

การกรองใน MongoDB ทำได้โดยใส่เงื่อนไขใน find() และใช้ query operator ที่ขึ้นต้นด้วย $

กรองค่าตรงตัว (เทียบเท่า WHERE column = value)#

db.products.find({ category: "Accessories" })
javascript

คืนเฉพาะสินค้าหมวด Accessories (5 รายการ)

find category in Compass

เปรียบเทียบตัวเลขด้วย gt,gt, lt, gte,gte, lte#

OperatorความหมายSQL เทียบเท่า
$gtมากกว่า>
$gteมากกว่าหรือเท่ากับ>=
$ltน้อยกว่า<
$lteน้อยกว่าหรือเท่ากับ<=
$neไม่เท่ากับ!=
$inอยู่ในชุดที่กำหนดIN (...)
// ราคามากกว่า 1000
db.products.find({ price: { $gt: 1000 } })
javascript

ผลลัพธ์:

nameprice
Mechanical Keyboard1890
4K Monitor8500
Webcam HD1200
Bluetooth Speaker1450

find price $gt in Compass

หลายเงื่อนไข — ค่าเริ่มต้นคือ AND#

เมื่อใส่หลายฟิลด์ในเงื่อนไขเดียว MongoDB ถือว่าต้องเป็นจริงทั้งคู่ (AND) โดยอัตโนมัติ

// หมวด Accessories และ stock > 10
db.products.find({ category: "Accessories", stock: { $gt: 10 } })
javascript

ผลลัพธ์:

namecategorystock
Wireless MouseAccessories25
Mechanical KeyboardAccessories12
Laptop StandAccessories30

(USB-C Hub และ Desk Lamp ถูกตัดเพราะ stock เป็น 0)

ใช้ $or สำหรับ “หรือ”#

db.products.find({
  $or: [
    { category: "Displays" },
    { rating: { $gte: 4.6 } }
  ]
})
javascript

คืนสินค้าที่เป็นหมวด Displays หรือ rating ≥ 4.6 — ได้ 4K Monitor (Displays), Mechanical Keyboard (4.8), Bluetooth Speaker (4.6)

ใช้ $in สำหรับชุดค่า#

// หมวดเป็น Displays หรือ Electronics
db.products.find({ category: { $in: ["Displays", "Electronics"] } })
javascript

สรุป: MongoDB กรองด้วยเงื่อนไขใน find() หลายฟิลด์คือ AND โดยปริยาย, $or สำหรับหรือ, $gt/$lt/... สำหรับเปรียบเทียบ และ $in สำหรับชุดค่า

📝 แบบฝึกหัด

  1. จงเขียน query หาสินค้าที่ rating ≥ 4.5 และ stock > 0 (หลายฟิลด์ในเงื่อนไขเดียว)
  2. จงเขียน query หาสินค้าหมวด Displays หรือ Electronics โดยใช้ $in
  3. จงเขียน query หาสินค้าที่ ราคา < 700 หรือ rating > 4.7 โดยใช้ $or
  4. จะเขียน query หา “สินค้าที่ stock ไม่เท่ากับ 0” ด้วย operator ใด?

10. sort, limit และ count#

เรียงลำดับ — sort()#

ใช้ 1 สำหรับน้อยไปมาก (ASC) และ -1 สำหรับมากไปน้อย (DESC) เหมือน ORDER BY ใน SQL

// เรียงราคาจากมากไปน้อย
db.products.find().sort({ price: -1 })
javascript

ผลลัพธ์ (ส่วนบน):

nameprice
4K Monitor8500
Mechanical Keyboard1890
Bluetooth Speaker1450
Webcam HD1200

จำกัดจำนวน — limit()#

ใช้ร่วมกับ sort() เพื่อดึง “top N” เหมือน LIMIT ใน SQL

// สินค้า 3 อันดับที่แพงที่สุด
db.products.find().sort({ price: -1 }).limit(3)
javascript

ผลลัพธ์: 4K Monitor, Mechanical Keyboard, Bluetooth Speaker

นับจำนวน — countDocuments()#

// นับสินค้าในหมวด Accessories ที่ stock > 10
db.products.countDocuments({ category: "Accessories", stock: { $gt: 10 } })
javascript

ผลลัพธ์: 3

สรุป: sort() เรียงลำดับ (1/-1), limit() จำกัดจำนวน, countDocuments() นับจำนวนเอกสารที่ตรงเงื่อนไข

📝 แบบฝึกหัด

  1. จงเขียน query หา สินค้า 3 อันดับที่ rating สูงที่สุด (ใช้ sort + limit)
  2. จงเขียนคำสั่ง นับสินค้าที่ stock = 0 (ผลลัพธ์ที่คาดว่าจะได้คือเท่าใด?)
  3. ถ้าต้องการเรียงสินค้าตามราคา จากน้อยไปมาก ต้องใช้ 1 หรือ -1 ใน sort?

11. Aggregation — จัดกลุ่มและสรุปข้อมูล#

Aggregation Pipeline ของ MongoDB เทียบเท่า GROUP BY รวมถึงการคำนวณ SUM, AVG, COUNT ใน SQL โดยเชื่อมขั้นตอน (stage) หลายขั้นเข้าด้วยกัน

หาค่าเฉลี่ยราคาแยกตามหมวด — $group#

db.products.aggregate([
  {
    $group: {
      _id: "$category",
      avgPrice: { $avg: "$price" },
      count: { $sum: 1 }
    }
  }
])
javascript

อธิบายแต่ละส่วน:

  • $group — จัดกลุ่มเอกสารตามฟิลด์ที่กำหนด
  • _id: "$category" — ฟิลด์ที่จะจัดกลุ่ม (ใช้ $ นำหน้าชื่อฟิลด์)
  • avgPrice: { $avg: "$price" } — คำนวณค่าเฉลี่ย price ของแต่ละกลุ่ม เก็บในชื่อ avgPrice
  • count: { $sum: 1 } — นับจำนวนเอกสารในแต่ละกลุ่ม (บวก 1 ทีละแถว)

ผลลัพธ์:

_id (category)avgPricecount
Accessories8965
Displays85001
Electronics13252

Aggregation

Aggregation Operators ที่ใช้บ่อย#

OperatorความหมายSQL เทียบเท่า
$sumผลรวม / นับ ($sum: 1)SUM() / COUNT()
$avgค่าเฉลี่ยAVG()
$min / $maxค่าต่ำ/สูงสุดMIN() / MAX()
// หาราคาสูงสุดและต่ำสุดในแต่ละหมวด
db.products.aggregate([
  {
    $group: {
      _id: "$category",
      maxPrice: { $max: "$price" },
      minPrice: { $min: "$price" }
    }
  }
])
javascript

สรุป: Aggregation Pipeline จัดกลุ่มและสรุปข้อมูลผ่านหลาย stage เริ่มต้นด้วย $group และใช้ $avg, $sum, $min, $max คำนวณ — เทียบเท่า GROUP BY และ aggregate functions ของ SQL

📝 แบบฝึกหัด

  1. จงเขียน aggregation หา ราคารวม (sum) ของสินค้าแยกตามหมวด โดยตั้งชื่อผลลัพธ์ว่า totalPrice
  2. จงเขียน aggregation หา rating เฉลี่ยของสินค้าทั้งหมด โดยไม่แบ่งหมวด (คำใบ้: ใช้ _id: null)
  3. ใน $group, ทำไมต้องมีเครื่องหมาย $ นำหน้าชื่อฟิลด์ เช่น "$price"?

12. update — แก้ไขข้อมูล#

updateOne() แก้ไขเอกสารแรกที่ตรงเงื่อนไข, updateMany() แก้ไขทุกเอกสารที่ตรง ใช้ update operator นำหน้าด้วย $

แก้ไขฟิลด์ด้วย $set#

// เปลี่ยนราคา Wireless Mouse
db.products.updateOne(
  { name: "Wireless Mouse" },
  { $set: { price: 690 } }
)
javascript
  • อาร์กิวเมนต์แรก { name: "Wireless Mouse" } — เงื่อนไขหาเอกสาร (เหมือน WHERE)
  • อาร์กิวเมนต์์ที่สอง { $set: { price: 690 } } — สิ่งที่จะเปลี่ยน ($set ตั้งค่าใหม่)

เพิ่มค่าตัวเลขด้วย $inc#

// เพิ่ม stock ทุกสินค้าหมวด Accessories ขึ้น 5
db.products.updateMany(
  { category: "Accessories" },
  { $inc: { stock: 5 } }
)
javascript

$inc (increment) เพิ่มค่าตัวเลขตามจำนวนที่กำหนด ใช้ค่าลบเพื่อลดได้

เพิ่มสมาชิกใน array ด้วย $push#

// เพิ่มแท็ก "sale" ให้ Wireless Mouse
db.products.updateOne(
  { name: "Wireless Mouse" },
  { $push: { tags: "sale" } }
)
javascript
Operatorการทำงาน
$setตั้งค่าฟิลด์ (สร้างใหม่ถ้ายังไม่มี)
$incเพิ่ม/ลดค่าตัวเลข
$pushเพิ่มสมาชิกต่อท้าย array
$unsetลบฟิลด์ออกจากเอกสาร

⚠️ คำเตือน: อย่าลืมใส่ update operator ($set, $inc ฯลฯ) หากเขียน { price: 690 } ตรง ๆ MongoDB จะพยายาม แทนที่เอกสารทั้งฉบับ ด้วย { price: 690 } ซึ่งมักไม่ใช่สิ่งที่ตั้งใจ

สรุป: updateOne/updateMany แก้ไขเอกสาร โดยอาร์กิวเมนต์แรกคือเงื่อนไข อาร์กิวเมนต์์ที่สองใช้ operator เช่น $set, $inc, $push

📝 แบบฝึกหัด

  1. จงเขียน updateOne เปลี่ยน rating ของ “Desk Lamp” เป็น 4.2 (ใช้ $set)
  2. จงเขียน updateMany ลด stock ของสินค้าหมวด Electronics ลง 3 (ใช้ $inc กับค่าลบ)
  3. จงเขียนคำสั่งเพิ่มแท็ก “new” ให้ “Webcam HD” (ใช้ $push)
  4. ถ้าเขียน db.products.updateOne({ name: "Desk Lamp" }, { price: 700 }) โดยไม่ใส่ $set จะเกิดอะไรขึ้น?

13. delete — ลบข้อมูล#

deleteOne() ลบเอกสารแรกที่ตรงเงื่อนไข, deleteMany() ลบทุกเอกสารที่ตรง เหมือน DELETE ใน SQL

ลบด้วยเงื่อนไข#

// ลบสินค้าที่ stock เป็น 0 (สินค้าหมด)
db.products.deleteMany({ stock: 0 })
javascript

คำสั่งนี้จะลบ USB-C Hub และ Desk Lamp (ทั้งคู่มี stock: 0)

ลบเอกสารเดียว#

db.products.deleteOne({ name: "4K Monitor" })
javascript

⚠️ คำเตือนสำคัญ: หากใส่เงื่อนไขว่าง {} จะลบเอกสาร ทั้งหมด ใน collection!

db.products.deleteMany({})  // ลบทุกเอกสารใน products
javascript

ให้ตรวจสอบเงื่อนไขเสมอก่อนรัน deleteMany

สรุป: deleteOne/deleteMany ลบเอกสารตามเงื่อนไข ระวังเงื่อนไขว่าง {} ที่จะลบทุกอย่าง

📝 แบบฝึกหัด

  1. จงเขียน deleteMany ลบสินค้าที่ stock = 0 — มีกี่รายการที่จะถูกลบ?
  2. จงเขียนคำสั่งลบสินค้า “4K Monitor” เฉพาะเอกสารเดียว
  3. คำสั่ง db.products.deleteMany({}) ทำอะไร? ควรระวังอะไร?

14. Schema Design — Embed vs Reference#

ใน RDBMS เราแยกข้อมูลเป็นหลายตารางแล้วเชื่อมด้วย foreign key + JOIN แต่ใน MongoDB มีแนวทางออกแบบ 2 แบบหลัก คือ ฝัง (Embed) และ อ้างอิง (Reference)

Embed — ฝังข้อมูลที่เกี่ยวข้องไว้ด้วยกัน#

เหมาะเมื่อข้อมูลถูกอ่านร่วมกันเสมอ และมีจำนวนไม่มาก (one-to-few) เช่นรีวิวสินค้าที่ฝังในเอกสารสินค้า

{
  name: "Wireless Mouse",
  price: 590,
  reviews: [
    { user: "Somchai", stars: 5, comment: "ดีมาก" },
    { user: "Nida", stars: 4, comment: "ใช้งานสะดวก" }
  ]
}
javascript

ข้อดี: ดึงข้อมูลครบใน query เดียว ไม่ต้อง JOIN อ่านเร็ว

Reference — เก็บ ID อ้างอิงข้าม collection#

เหมาะเมื่อข้อมูลมีจำนวนมาก ถูกใช้ซ้ำ หรือเปลี่ยนแปลงบ่อย (one-to-many, many-to-many) เช่นคำสั่งซื้อที่อ้างอิงผู้ใช้และสินค้าแยก collection

// collection: orders
{
  orderNo: "ORD-001",
  userId: ObjectId("..."),       // อ้างอิง users
  items: [
    { productId: ObjectId("..."), qty: 2 }  // อ้างอิง products
  ]
}
javascript

Embed vs Reference

เลือกแบบไหน?#

เกณฑ์แนะนำ
ข้อมูลน้อย อ่านร่วมกันเสมอ ไม่ค่อยเปลี่ยนEmbed
ข้อมูลมาก ใช้ซ้ำข้ามเอกสาร เปลี่ยนบ่อยReference
ความสัมพันธ์แบบ one-to-fewEmbed
ความสัมพันธ์แบบ many-to-manyReference

สรุป: MongoDB ให้เลือกฝังหรืออ้างอิงตามลักษณะข้อมูล ฝังเมื่ออ่านร่วมกันและมีไม่มาก อ้างอิงเมื่อมีจำนวนมากหรือใช้ซ้ำ — การออกแบบที่ดีคือหัวใจของการใช้ NoSQL ให้มีประสิทธิภาพ

📝 แบบฝึกหัด

  1. ข้อมูล “ที่อยู่จัดส่ง” ของผู้ใช้ (บ้านเลขที่ ถนน ตำบล อำเภอ จังหวัด) ควร embed ในเอกสารผู้ใช้ หรือ reference collection แยก? เพราะอะไร?
  2. ข้อมูล “ความคิดเห็น” ในเว็บบอร์ดที่แต่ละโพสต์มีคอมเมนต์ นับพัน ควร embed หรือ reference? เพราะอะไร?
  3. จงยกตัวอย่างความสัมพันธ์แบบ one-to-few ที่เหมาะกับการ embed 1 กรณี

15. ตัวอย่าง Prompt สำหรับสร้าง Query ด้วย Generative AI#

สามารถใช้ ChatGPT หรือ Claude ช่วยสร้าง MongoDB query ได้ โดยให้บริบทที่ชัดเจน

Prompt 1 — ค้นหาและกรอง:

collection products มีฟิลด์ name, price, category, stock, rating จงเขียน MongoDB query หาสินค้าหมวด Electronics ที่ราคาต่ำกว่า 1500 และ stock มากกว่า 10 เรียงตามราคาน้อยไปมาก

Prompt 2 — Aggregation:

จาก collection products ที่มีฟิลด์ category และ price จงเขียน MongoDB aggregation หาราคาเฉลี่ยและจำนวนสินค้าแยกตามหมวด เรียงตามราคาเฉลี่ยจากมากไปน้อย

Prompt 3 — สร้างข้อมูลตัวอย่าง:

Generate MongoDB insertMany statements for a products collection with fields name, price, category, stock, and rating, using 10 realistic sample products across categories Electronics, Accessories, and Displays.

เคล็ดลับ: ยิ่งบอกชื่อ collection, ฟิลด์ และสิ่งที่ต้องการชัดเท่าไหร่ query ที่ได้ก็ยิ่งตรงความต้องการมากขึ้น


16. สรุป#

บทความนี้ครอบคลุมพื้นฐาน NoSQL Database และ MongoDB ตั้งแต่แนวคิดไปจนถึงการปฏิบัติ:

  • NoSQL — ฐานข้อมูลที่ schema ยืดหยุ่น รองรับข้อมูลปริมาณมหาศาลและรูปแบบหลากหลาย
  • JSON — รูปแบบข้อความ key-value ที่เป็นรากฐานของ document database
  • ประเภทของ NoSQL — Document, Key-Value, Wide Column, Graph แต่ละแบบเหมาะกับงานต่างกัน
  • MongoDB — Document database ที่เก็บข้อมูลเป็น BSON, เทียบ table/row กับ collection/document
  • Community Server & Compass — ติดตั้งฐานข้อมูลบนเครื่องและจัดการผ่าน GUI
  • CRUDinsertOne/insertMany, find, updateOne/updateMany, deleteOne/deleteMany
  • Query operators$gt, $lt, $or, $in สำหรับกรองข้อมูล
  • Aggregation$group กับ $avg, $sum, $max, $min สำหรับสรุปข้อมูล
  • Schema design — Embed vs Reference เลือกตามลักษณะความสัมพันธ์

แต่ละหัวข้อมี 📝 แบบฝึกหัด ให้ฝึกทบทวน เมื่อเข้าใจพื้นฐานเหล่านี้แล้ว คุณจะสามารถออกแบบและจัดการฐานข้อมูล NoSQL สำหรับแอปพลิเคชันที่ต้องการความยืดหยุ่นและความเร็ว พร้อมต่อยอดสู่การพัฒนา API, real-time application และระบบที่รองรับข้อมูลปริมาณมหาศาล

พื้นฐาน NoSQL Database และ MongoDB
ผู้เขียน กานต์ ยงศิริวิทย์ / Karn Yongsiriwit
เผยแพร่เมื่อ July 11, 2026
ลิขสิทธิ์ CC BY-NC-SA 4.0

กำลังโหลดความคิดเห็น...

ความคิดเห็น 0