สมัครสมาชิก VIP เพียง 1,900 บาท/ปี ดาวน์โหลดสินค้าดิจิทัลฟรีทุกรายการที่มีสัญลักษณ์ VIP ดูรายละเอียด
naiyachonponthong@gmail.com | 0965073584
Real-Programmers

เจาะลึกระบบ DATA ROUTING & CRUD (บันทึกและดึงข้อมูลพื้นฐาน) บน Google Sheets

เจาะลึกระบบ DATA ROUTING & CRUD (บันทึกและดึงข้อมูลพื้นฐาน) บน Google Sheets

หลังจากที่เราได้เรียนรู้วิธีการใช้ฟังก์ชัน initializeSheets() ในการเตรียมหน้าแท็บฐานข้อมูลให้พร้อมใช้งานไปแล้วในบทความก่อนหน้านี้ ตอนนี้ระบบของเรามีหน้าตาโครงสร้างตารางที่สวยงามและพร้อมรับแรงกระแทกจากข้อมูลแล้วครับ

แต่คำถามคือ "แล้วเราจะเอาข้อมูลจากหน้าเว็บส่งเข้าไปบันทึกได้อย่างไร? และเมื่อบันทึกไปแล้ว จะดึงข้อมูลเฉพาะเจาะจงกลับออกมาแสดงผลได้อย่างไร?"

ยินดีต้อนรับเข้าสู่บทความตอนที่ 2 ในหมวด DATA ROUTING & CRUD ซึ่งเป็นหัวใจสำคัญของการสร้างแอปพลิเคชันทุกประเภทในโลกใบนี้ครับ!

1. ทำความรู้จักคำว่า "DATA ROUTING" และ "CRUD"

สำหรับมือใหม่ สองคำนี้อาจจะฟังดูเหมือนศัพท์เทคนิคขั้นสูง แต่ถ้าเราแกะความหมายออกมาจริงๆ มันคือเรื่องที่เข้าใจง่ายมากๆ ครับ

Data Routing คืออะไร?

คำว่า Routing (เราติ้ง) แปลว่า "การเลือกเส้นทาง" ดังนั้นในทางซอฟต์แวร์ Data Routing คือ การเขียนโค้ดเพื่อควบคุมทิศทางของข้อมูลที่วิ่งเข้ามา เช่น เมื่อหน้าบ้านส่งข้อมูลมา โค้ดส่วนนี้จะทำหน้าที่คิดว่า "ข้อมูลนี้เป็นข้อมูลของระบบไหน? อ๋อ... เป็นข้อมูลเข้างานของพนักงาน งั้นต้องวิ่งไปส่งให้ฟังก์ชันบันทึกเวลาทำงานนะ อย่าไปส่งผิดแท็บ" มันเหมือนเป็นบุรุษไปรษณีย์ที่คอยคัดแยกจดหมายให้ไปถูกบ้านนั่นเอง


CRUD คืออะไร?

คำนี้เป็นตัวย่อของ 4 ฟังก์ชันพื้นฐานที่ระบบฐานข้อมูลทั่วโลกต้องมี:

  • C - Create: การสร้างหรือบันทึกข้อมูลใหม่ลงตาราง

  • R - Read: การอ่านหรือดึงข้อมูลจากตารางมาแสดงผล (เช่น การค้นหาประวัติ)

  • U - Update: การแก้ไขข้อมูลเดิมที่มีอยู่แล้วให้เป็นค่าใหม่

  • D - Delete: การลบข้อมูลที่ไม่ต้องการออกจากระบบ

ในบทความนี้ เราจะโฟลว์ไปที่ 2 ตัวหลักที่สำคัญที่สุดสำหรับมือใหม่ก่อน นั่นคือ Create (บันทึกข้อมูล) และ Read (ดึงข้อมูลด้วยเงื่อนไขเฉพาะเจาะจง) ครับ

2. ทำไมเราต้องเขียนโค้ดแยกส่วน CRUD ออกจากกัน?

โปรแกรมเมอร์มือใหม่หลายคนมักจะเขียนโค้ดทุกอย่างรวมกันเป็นก้อนเดียวขนาดยักษ์ (ที่เรียกว่า Spaghetti Code) เช่น เขียนโค้ดเช็คหน้าชีท บันทึกข้อมูล และจัดฟอร์แมตในฟังก์ชันเดียวกันทั้งหมด

การทำแบบนั้นจะทำให้เกิดปัญหาใหญ่ตามมา:

  1. หาจุดพังยาก: เวลาที่ระบบบันทึกข้อมูลไม่ได้ คุณต้องไล่โค้ดตั้งแต่บรรทัดแรกจนถึงบรรทัดสุดท้ายเพื่อหาจุดผิดพลาด

  2. โค้ดซ้ำซ้อน: ถ้าคุณมีหน้าเว็บ 3 หน้าที่ต้องการบันทึกประวัติการใช้งานเหมือนกัน คุณจะต้องเขียนโค้ดบันทึกซ้ำๆ กันทั้ง 3 จุด

การสร้างระบบ Data Routing เพื่อส่งงานต่อไปยังฟังก์ชัน CRUD ที่แยกกันอย่างเป็นสัดส่วน จึงช่วยให้โค้ดของคุณสะอาด ปลอดภัย และหากต้องการแก้ไขฟังก์ชันบันทึกในอนาคต คุณก็แค่มาแก้ที่จุดเดียว โดยไม่กระทบกับระบบค้นหาข้อมูลเลยครับ

3. ส่องโค้ดตัวอย่าง: ระบบจัดการข้อมูลพื้นฐาน

นี่คือตัวอย่างการเขียนโค้ดระบบ Data Routing และฟังก์ชัน CRUD สำหรับบันทึกข้อมูลผู้ใช้งาน และการค้นหาข้อมูลด้วยเงื่อนไข (เช่น ค้นหาประวัติด้วยเบอร์โทรศัพท์) ซึ่งถูกออกแบบมาให้เชื่อมต่อกับหน้าชีทที่เราเตรียมไว้ครับ

/**
 * หมวดหมู่: DATA ROUTING
 * ฟังก์ชัน: routeDataAction
 * วัตถุประสงค์: ทำหน้าที่เป็นตัวคัดแยกและส่งต่อคำสั่งจากหน้าเว็บไปยังฟังก์ชัน CRUD ที่ถูกต้อง
 */
function routeDataAction(request) {
  var action = request.action; // รับคำสั่งว่าต้องการทำอะไร เช่น 'save' หรือ 'search'
  var payload = request.data;  // รับก้อนข้อมูลที่ส่งมา
  
  switch(action) {
    case "create_user":
      return createUserRow(payload); // ส่งต่อไปฟังก์ชันบันทึกข้อมูล
    case "get_user_by_phone":
      return readUserByPhone(payload.phone); // ส่งต่อไปฟังก์ชันค้นหาด้วยเบอร์โทร
    default:
      return { status: "error", message: "ไม่พบคำสั่งที่ระบุในระบบ" };
  }
}

/**
 * หมวดหมู่: CRUD - CREATE
 * ฟังก์ชัน: createUserRow
 * วัตถุประสงค์: บันทึกรายชื่อและข้อมูลผู้ใช้งานใหม่ลงใน Google Sheets
 */
function createUserRow(data) {
  try {
    var spreadsheet = SpreadsheetApp.getActiveSpreadsheet();
    var sheet = spreadsheet.getSheetByName("User_Records"); // วิ่งไปหาแท็บที่เก็บข้อมูลผู้ใช้
    
    // ตรวจสอบความปลอดภัย: หากหน้าชีทโดนลบ ให้ระบบแจ้งเตือนแทนการพัง
    if (!sheet) {
      return { status: "error", message: "ไม่พบหน้าชีทระบบ กรุณารันตั้งค่าเริ่มต้นก่อน" };
    }
    
    // สร้างแถวข้อมูลใหม่ตามลำดับคอลัมน์ [ID, ชื่อ, เบอร์โทรศัพท์, วันที่สมัคร]
    var newRow = [
      "UID-" + new Date().getTime(), // สร้าง ID แบบสุ่มจากเวลาปัจจุบัน
      data.fullName,
      data.phoneNumber,
      new Date()
    ];
    
    // ต่อท้ายแถวข้อมูลใหม่ลงในตาราง
    sheet.appendRow(newRow);
    
    return { status: "success", message: "บันทึกข้อมูลผู้ใช้งานเรียบร้อยแล้ว!" };
    
  } catch(error) {
    return { status: "error", message: "เกิดข้อผิดพลาดในการบันทึก: " + error.toString() };
  }
}

/**
 * หมวดหมู่: CRUD - READ
 * ฟังก์ชัน: readUserByPhone
 * วัตถุประสงค์: ค้นหาข้อมูลผู้ใช้งานจากเบอร์โทรศัพท์ที่ระบุ
 */
function readUserByPhone(phoneToFind) {
  try {
    var spreadsheet = SpreadsheetApp.getActiveSpreadsheet();
    var sheet = spreadsheet.getSheetByName("User_Records");
    
    if (!sheet) return { status: "error", message: "ไม่พบหน้าชีทระบบ" };
    
    // ดึงข้อมูลทั้งหมดในชีทออกมา (ยกเว้นแถวแรกที่เป็นหัวตาราง)
    var lastRow = sheet.getLastRow();
    if (lastRow <= 1) {
      return { status: "empty", message: "ยังไม่มีข้อมูลผู้ใช้งานในระบบ" };
    }
    
    // ดึงข้อมูลทั้งหมดตั้งแต่แถวที่ 2 คอลัมน์ที่ 1 ถึงแถวสุดท้าย
    var dataRange = sheet.getRange(2, 1, lastRow - 1, sheet.getLastColumn());
    var allRows = dataRange.getValues();
    
    // วนลูปเพื่อค้นหาข้อมูล (คอลัมน์ที่ 3 หรือ Index 2 คือเบอร์โทรศัพท์)
    for (var i = 0; i < allRows.length; i++) {
      var currentRow = allRows[i];
      var userPhone = currentRow[2].toString().trim();
      
      if (userPhone === phoneToFind.toString().trim()) {
        // ถ้าเจอข้อมูลที่ตรงกัน ให้ส่งก้อนข้อมูลกลับออกไปทันที
        return {
          status: "found",
          data: {
            userId: currentRow[0],
            fullName: currentRow[1],
            phoneNumber: currentRow[2],
            registerDate: currentRow[3]
          }
        };
      }
    }
    
    // หากวนลูปจนจบแล้วยังไม่เจอเบอร์โทรที่ระบุ
    return { status: "not_found", message: "ไม่พบข้อมูลผู้ใช้งานที่ผูกกับเบอร์โทรศัพท์นี้" };
    
  } catch(error) {
    return { status: "error", message: "เกิดข้อผิดพลาดในการค้นหา: " + error.toString() };
  }
}


1. Data Routing — ตัวคัดแยกคำสั่ง หน้าที่ของฟังก์ชันนี้คือ:
  • รับคำสั่งจาก Frontend 
  • ตรวจสอบประเภทคำสั่ง 
  • ส่งต่อไปยังฟังก์ชันที่ถูกต้อง


  • function routeDataAction(request) {
    
      var action = request.action;
      var payload = request.data;
    
      switch(action) {
    
        case "create_user":
          return createUserRow(payload);
    
        case "get_user_by_phone":
          return readUserByPhone(payload.phone);
    
        default:
          return {
            status: "error",
            message: "ไม่พบคำสั่งที่ระบุ"
          };
      }
    }


2. CRUD — CREATE (บันทึกข้อมูล)
ฟังก์ชันนี้ใช้สำหรับ:
  • รับข้อมูลผู้ใช้ใหม่
  • สร้าง ID
  • บันทึกลง Google Sheets

function createUserRow(data) {

  try {

    var spreadsheet = SpreadsheetApp.getActiveSpreadsheet();

    var sheet = spreadsheet.getSheetByName("User_Records");

    if (!sheet) {
      return {
        status: "error",
        message: "ไม่พบหน้าชีทระบบ"
      };
    }

    var newRow = [

      "UID-" + new Date().getTime(),

      data.fullName,

      data.phoneNumber,

      new Date()
    ];

    sheet.appendRow(newRow);

    return {
      status: "success",
      message: "บันทึกข้อมูลเรียบร้อยแล้ว"
    };

  } catch(error) {

    return {
      status: "error",
      message: error.toString()
    };
  }
}



3. CRUD — READ (ค้นหาข้อมูล)
ฟังก์ชันนี้ใช้สำหรับ:
  • อ่านข้อมูลจากชีท
  • ค้นหาด้วยเบอร์โทรศัพท์
  • ส่งข้อมูลกลับ


function readUserByPhone(phoneToFind) {

  try {

    var spreadsheet = SpreadsheetApp.getActiveSpreadsheet();

    var sheet = spreadsheet.getSheetByName("User_Records");

    if (!sheet) {
      return {
        status: "error",
        message: "ไม่พบหน้าชีทระบบ"
      };
    }

    var lastRow = sheet.getLastRow();

    if (lastRow <= 1) {

      return {
        status: "empty",
        message: "ยังไม่มีข้อมูล"
      };
    }

    var dataRange = sheet.getRange(
      2,
      1,
      lastRow - 1,
      sheet.getLastColumn()
    );

    var allRows = dataRange.getValues();

    for (var i = 0; i < allRows.length; i++) {

      var currentRow = allRows[i];

      var userPhone = currentRow[2]
        .toString()
        .trim();

      if (
        userPhone ===
        phoneToFind.toString().trim()
      ) {

        return {

          status: "found",

          data: {

            userId: currentRow[0],

            fullName: currentRow[1],

            phoneNumber: currentRow[2],

            registerDate: currentRow[3]
          }
        };
      }
    }

    return {
      status: "not_found",
      message: "ไม่พบข้อมูล"
    };

  } catch(error) {

    return {
      status: "error",
      message: error.toString()
    };
  }
}






5. เทคนิคสำหรับมือใหม่: วิธีป้องกันระเบิดเวลาในระบบ CRUD

การเขียนระบบจัดการข้อมูลบน Google Sheets มีจุดที่ต้องระวังเป็นพิเศษเพื่อไม่ให้ระบบช้าหรือเกิด Error เมื่อมีข้อมูลจำนวนมาก:

  1. ใช้คำสั่ง appendRow อย่างระมัดระวัง: คำสั่ง sheet.appendRow() เป็นวิธีบันทึกข้อมูลที่ง่ายที่สุดเพราะมันจะวิ่งไปหาแถวว่างแถวสุดท้ายให้เราเองอัตโนมัติ แต่อย่าลืมตรวจสอบสิทธิ์การเขียนไฟล์ให้เรียบร้อย และตรวจสอบว่าไม่มีการเผลอเคาะเว้นวรรคทิ้งไว้ในแถวล่างๆ ของหน้าชีท ไม่งั้นข้อมูลจะโดนโยนลงไปต่อท้ายแถวที่ว่างจริงๆ ซึ่งอาจอยู่ไกลมาก

  2. จัดการกับช่องว่างและการตัดคำ (Trim): สังเกตในโค้ดค้นหา จะมีการใช้คำสั่ง .toString().trim() ทุกครั้งก่อนนำมาเปรียบเทียบกัน เพราะบ่อยครั้งที่ผู้ใช้งานเผลอกดเคาะสเปซบาร์เว้นวรรคหน้าหรือหลังเบอร์โทรศัพท์ตอนกรอกฟอร์ม การใช้ .trim() จะช่วยตัดช่องว่างที่มองไม่เห็นเหล่านั้นออกไป ทำให้การค้นหาแม่นยำขึ้น 100%

  3. ใส่คำสั่ง try...catch ครอบไว้เสมอ: ในโลกความเป็นจริง อะไรก็เกิดขึ้นได้ หน้าชีทอาจโดนพนักงานลบ อินเทอร์เน็ตอาจหลุดชั่วขณะ การใช้ try...catch จะช่วยดักจับ Error แล้วส่งข้อความเตือนที่อ่านรู้เรื่องกลับไปบอกผู้ใช้ แทนการปล่อยให้ระบบค้างเติ่งไปเฉยๆ ครับ

    สรุป

    การเข้าใจสถาปัตยกรรม Data Routing & CRUD จะเปลี่ยนมุมมองของคุณจากการเขียนสคริปต์แผ่นเดียวให้กลายเป็นการสร้างระบบฐานข้อมูลที่แท้จริง ซึ่งโค้ดรูปแบบแยกหน้าที่แบบนี้ จะมีความยืดหยุ่นสูงมาก และพร้อมที่จะถูกนำไปอัปเกรดเพื่อเปลี่ยนวิธีการจัดเก็บข้อมูลให้อยู่ในรูปแบบที่เหนือชั้นขึ้นไปอีกในบทความตอนหน้า นั่นคือ การมัดรวมข้อมูลเก็บเป็นก้อน JSON ในเซลล์เดียว ครับ ติดตามอ่านต่อได้เลย!

ความคิดเห็น
ทักผ่าน LINE Messenger ส่งอีเมล โทรหาเรา
ติดต่อ