PlusMagi's Blog By Pitt Phunsanit Backend,Database PHP: การอัพโหลดไฟล์หลายไฟล์

PHP: การอัพโหลดไฟล์หลายไฟล์

ในฐานะ System Specialist และ Senior Database Architect เราทราบดีว่าการจัดการกระบวนการอัพโหลดไฟล์หลายไฟล์ (Multiple File Uploads) เป็นงานที่ซับซ้อน เพราะมันไม่ได้จบแค่การรับข้อมูลด้วย PHP แต่รวมถึงการออกแบบสถาปัตยกรรมของ Metadata ในระดับฐานข้อมูลด้วย

ในทางปฏิบัติ, PHP จะทำหน้าที่จัดการ Input/Output (I/O) ของไฟล์จริงผ่านฟังก์ชันเช่น move_uploaded_file() ส่วน PostgreSQL คือผู้รับผิดชอบในการจัดเก็บและประมวลผลชุดข้อมูลเกี่ยวกับไฟล์เหล่านั้น (Metadata) เช่น ชื่อไฟล์, ขนาด, และประเภท MIME

การออกแบบ Metadata สำหรับ Batch Processing ใน PostgreSQL

เมื่อระบบต้องรองรับการอัพโหลดไฟล์จำนวนมากในคราวเดียว (Batch Data), การเขียนโค้ดที่วนลูปเพื่อ INSERT ข้อมูลทีละรายการจะทำให้ประสิทธิภาพลดลงอย่างรวดเร็ว แนวทางสถาปัตยกรรมที่ดีคือการออกแบบให้ฐานข้อมูลสามารถรับชุดข้อมูลขนาดใหญ่เข้ามาเป็นก้อนเดียว และแยกส่วนข้อมูลเหล่านั้นออกมาประมวลผลในรูปแบบแถว (Row) ได้ทันที

เราจึงใช้โครงสร้างข้อมูลแบบ JSONB ใน PostgreSQL เพื่อเก็บ Metadata ของไฟล์ทั้งหมดที่ถูกส่งมาจาก PHP ซึ่งให้ความยืดหยุ่นสูงในการขยาย Schema และเมื่อถึงเวลาประมวลผล เราจะใช้ฟังก์ชันเฉพาะทางของ Postgres คือ jsonb_array_elements() ร่วมกับ Common Table Expressions (CTE) เพื่อแยกชุดข้อมูล JSONB ให้กลายเป็นแถวข้อมูลมาตรฐาน

การใช้ jsonb_array_elements สำหรับ Bulk Data Ingestion

หัวใจสำคัญของการจัดการ Batch Metadata คือการแปลงโครงสร้างข้อมูลที่ซับซ้อน (JSONB Array) ให้เป็นตารางเสมือนจริง (Virtual Table) ซึ่งทำให้เราสามารถเขียน Logic การ Query หรือ Insert ข้อมูลสำหรับไฟล์แต่ละไฟล์ได้อย่างชัดเจนและมีประสิทธิภาพสูง

SQL

-- 1. สมมติว่า PHP ได้ส่งชุด Metadata มาในรูปแบบ JSONB Array -- SELECT jsonb_array_elements('[{"filename": "photo_a.jpg", "size": 2048, "mime_type": "image/jpeg"}, {"filename": "doc_b.pdf", "size": 5120, "mime_type": "application/pdf"}]')::jsonb AS file_record; -- 2. การใช้ CTE เพื่อแยกข้อมูลเป็นแถว (Unnesting) WITH uploaded_files AS ( SELECT jsonb_array_elements('[{"filename": "photo_a.jpg", "size": 2048, "mime_type": "image/jpeg"}, {"filename": "doc_b.pdf", "size": 5120, "mime_type": "application/pdf"}]')::jsonb AS file_record ) SELECT (file_record ->> 'filename') AS filename, (file_record ->> 'mime_type') AS mime_type, (file_record ->> 'size')::integer AS file_size FROM uploaded_files;

คำอธิบายทางสถาปัตยกรรม:

  • jsonb_array_elements(...): ฟังก์ชันนี้ทำหน้าที่เป็นตัวแยกส่วน (Unnesting) โดยรับ JSONB Array เข้ามา และสร้างแถวข้อมูลเสมือนสำหรับแต่ละ Object ภายใน Array
  • ->> 'key': เป็น Operator ที่ใช้ดึงค่าของ Key ออกมาในรูปแบบข้อความ (Text) ซึ่งเหมาะสำหรับการนำไปใช้งานต่อในการ Query หรือการแปลงชนิดข้อมูล
  • CTE uploaded_files ช่วยให้เราจำลองกระบวนการรับชุดข้อมูลขนาดใหญ่เข้ามาแยกส่วนก่อนที่จะทำการ Insert เข้าสู่ตารางหลักอย่างเป็นระบบ ทำให้โค้ดมีความอ่านง่ายและสามารถขยาย Logic ในภายหลังได้ง่ายขึ้น

สรุปข้อสังเกตทางสถาปัตยกรรม (Architectural Conclusion)

ในมุมมองของ Senior Database Architect การจัดการไฟล์หลายไฟล์ที่สมบูรณ์แบบต้องแยกหน้าที่อย่างชัดเจน: PHP จัดการ I/O ของไฟล์จริง, และ PostgreSQL ต้องรับผิดชอบ Metadata ด้วยหลักการ Bulk Processing

การใช้ JSONB ร่วมกับฟังก์ชัน jsonb_array_elements() ไม่เพียงแต่ช่วยเพิ่มประสิทธิภาพในการประมวลผลชุดข้อมูลขนาดใหญ่เท่านั้น แต่ยังทำให้ Schema มีความยืดหยุ่น (Schema Flexibility) สูงมาก ซึ่งเป็นคุณสมบัติสำคัญที่ระบบระดับองค์กรต้องมี เพื่อให้สามารถรองรับการเปลี่ยนแปลงของประเภทไฟล์หรือ Metadata ใหม่ๆ ได้ในอนาคตโดยไม่ต้องแก้ไขโครงสร้างฐานข้อมูลหลักบ่อยครั้ง