เขียน MongoDB Query ให้ชัดด้วย Filter, Projection, Sort และ Limit
ออกแบบ query ให้ดึงเฉพาะ document และ field ที่จำเป็น พร้อมเรียงและจำกัดผลลัพธ์อย่างเหมาะสม เพื่อให้โค้ดอ่านง่ายและลดงานของฐานข้อมูล

ภาพรวม
Query ใน MongoDB จะเร็วหรือช้า มักไม่ได้เริ่มที่ server แรงแค่ไหน แต่เริ่มที่เรา “ถามคำถาม” ชัดแค่ไหน
คำสั่งพื้นฐานที่ใช้บ่อยคือ filter, projection, sort, limit ฟังดูธรรมดา แต่ถ้าใช้ดี ๆ จะทำให้โค้ดอ่านง่ายขึ้นมาก และช่วยให้ database ทำงานน้อยลงจริง 🚀
filter คือเงื่อนไขว่าอยากได้เอกสารไหน เช่นหา user ที่ status เป็น active อย่า query กว้างเกินจำเป็น เพราะการดึงทุกอย่างแล้วค่อยกรองใน app คือการย้ายงานหนักจาก database มาไว้ใน code
ตัวอย่างที่ดีคือ find({ status: 'active', role: 'student' }) อ่านแล้วรู้ทันทีว่าต้องการอะไร และถ้ามี index ที่เหมาะกับ status, role MongoDB ก็มีโอกาสวิ่งสั้นลง ไม่ต้องไล่อ่านทั้ง collection
projection คือการบอกว่าอยากได้ field ไหนกลับมา หลายคนลืมส่วนนี้ แล้วปล่อยให้ MongoDB ส่ง document ทั้งก้อนกลับมา ทั้งที่หน้าเว็บต้องการแค่ name กับ email
ใช้แบบนี้จะชัดกว่า find(filter, { projection: { name: 1, email: 1 } }) ข้อมูลที่เดินทางน้อยลง memory ใช้น้อยลง response ก็เบาลง โดยเฉพาะ document ที่มี array ใหญ่ ๆ หรือ field ยาว ๆ
แต่ projection ควรใช้แบบอ่านง่าย อย่าผสม include กับ exclude มั่ว ๆ ยกเว้น _id ที่ปิดได้ เช่น { _id: 0, name: 1 } ทีมอ่านต่อจะไม่ต้องเดาว่า query นี้ตั้งใจเอาอะไร
sort คือการเรียงผลลัพธ์ เช่น sort({ createdAt: -1 }) เพื่อเอาของใหม่ขึ้นก่อน จุดสำคัญคือ sort อาจแพงมาก ถ้าไม่มี index รองรับ MongoDB อาจต้องดึงผลลัพธ์จำนวนมากมาเรียงใน memory
ถ้า query ใช้ filter ตาม status แล้ว sort ตาม createdAt ให้คิดถึง compound index เช่น { status: 1, createdAt: -1 } เพราะ database จะกรองและเรียงได้เป็นจังหวะเดียวกัน ไม่ต้องทำงานซ้ำซ้อน
limit คือการจำกัดจำนวนผลลัพธ์ ใช้ทุกครั้งที่หน้า UI ไม่ได้ต้องการทั้งหมด เช่น feed, list, search suggestion limit(20) ดีกว่าปล่อย query เปิดกว้าง แล้วหวังว่าข้อมูลจะไม่เยอะ
ลำดับการคิดที่ดีคือ กรองให้แคบด้วย filter เลือก field ด้วย projection เรียงเท่าที่จำเป็นด้วย sort แล้วตัดจำนวนด้วย limit
ใน driver เราอาจเขียนเป็น chain แบบอ่านง่าย collection.find(filter) .project({ title: 1, createdAt: 1 }) .sort({ createdAt: -1 }) .limit(20)
สิ่งที่ควรเลี่ยงคือ query ที่ฉลาดเกินไปในบรรทัดเดียว เงื่อนไขซ้อนหลายชั้น ชื่อ field ไม่สื่อความหมาย หรือ magic number เช่น limit(37) ถ้าจำเป็นให้แยกตัวแปร const pageSize = 20 const filter = { status: 'published' }
อีกนิสัยที่ดีคือใช้ explain() เพื่อดูว่า query ใช้ index ไหม ดู keysExamined กับ docsExamined ถ้า docsExamined สูงมากแต่ผลลัพธ์น้อย แปลว่า database กำลังเดินไกลเกินไป ควรทบทวน filter หรือ index
Query ที่ดีไม่ใช่แค่เร็ว แต่ต้องอ่านแล้วเข้าใจเจตนา คนต่อไปควรรู้ว่าเรากรองอะไร เอา field ไหน เรียงเพื่ออะไร และจำกัดผลลัพธ์เพราะหน้าใช้งานต้องการเท่าไหร่
MongoDB ไม่ได้ช้าจากการใช้ find() แต่ช้าจากการถามกว้างเกิน ส่งข้อมูลเกิน เรียงโดยไม่มีทางลัด และไม่เคยวัดผล
เขียน query ให้เหมือนเขียนประโยคสั้น ๆ ถามให้ชัด เอาเท่าที่ใช้ เรียงเท่าที่จำเป็น จำกัดตั้งแต่ต้น แค่นี้โค้ดก็น่าอ่านขึ้น และ database ก็เหนื่อยน้อยลง 🙂
แนวทางนำไปใช้
- นำแนวคิดจากโพสต์นี้ไปทดลองกับงานจริงของคุณ
- แยกเป็นขั้นตอนเล็ก ๆ แล้วทำทีละส่วน
- บันทึกผลลัพธ์และสิ่งที่เรียนรู้เพื่อต่อยอด
สรุป
ออกแบบ query ให้ดึงเฉพาะ document และ field ที่จำเป็น พร้อมเรียงและจำกัดผลลัพธ์อย่างเหมาะสม เพื่อให้โค้ดอ่านง่ายและลดงานของฐานข้อมูล