Cloud Function จะนำเข้าข้อมูล CSV ไปยัง Google ชีตโดยอัตโนมัติ

1. บทนำ

เป้าหมายของ Codelab นี้คือเพื่อให้คุณเข้าใจวิธีเขียน Cloud Function เพื่อโต้ตอบกับการอัปโหลดไฟล์ CSV ไปยัง Cloud Storage เพื่ออ่านเนื้อหาและใช้อัปเดตสเปรดชีตใน Google ชีตโดยใช้ API ของชีต

e9c78061022a6760.png

การกระทำนี้อาจมองว่าเป็นการทำงานอัตโนมัติของการ "นำเข้าเป็น CSV" ด้วยตนเอง ครั้งแรก ซึ่งทำให้มั่นใจว่าคุณสามารถวิเคราะห์ข้อมูล (ซึ่งอาจสร้างขึ้นโดยทีมอื่น) ในสเปรดชีตได้ในทันทีที่มีข้อมูล

นี่คือลักษณะของการติดตั้งใช้งาน :

52df703605ae4bd3.png

2. การตั้งค่าและข้อกำหนด

การตั้งค่าสภาพแวดล้อมตามเวลาที่สะดวก

  1. ลงชื่อเข้าใช้ Cloud Console และสร้างโปรเจ็กต์ใหม่หรือใช้โปรเจ็กต์ที่มีอยู่ซ้ำ (หากยังไม่มีบัญชี Gmail หรือ G Suite คุณต้องสร้างบัญชี)

dMbN6g9RawQj_VXCSYpdYncY-DbaRzr2GbnwoV7jFf1u3avxJtmGPmKpMYgiaMH-qu80a_NJ9p2IIXFppYk8x3wyymZXavjglNLJJhuXieCem56H30hwXtd8PvXGpXJO9gEUDu3cZw

ci9Oe6PgnbNuSYlMyvbXF1JdQyiHoEgnhl4PlV_MFagm2ppzhueRkqX4eLjJllZco_2zCp0V0bpTupUSKji9KkQyWqj11pqit1K1faS1V6aFxLGQdkuzGp4rsQTan7F01iePL5DtqQ

8-tA_Lheyo8SscAVKrGii2coplQp2_D1Iosb2ViABY0UUO1A8cimXUu6Wf1R9zJIRExL5OB2j946aIiFtyKTzxDcNnuznmR45vZ2HMoK3o67jxuoUJCAnqvEX6NgPGFjCVNgASc-lg

โปรดจดจำรหัสโปรเจ็กต์ ซึ่งเป็นชื่อที่ไม่ซ้ำกันในโปรเจ็กต์ Google Cloud ทั้งหมด (ชื่อด้านบนมีคนใช้แล้ว และจะใช้ไม่ได้ ขออภัย) และจะมีการอ้างอิงใน Codelab ว่า PROJECT_ID ในภายหลัง

  1. ถัดไป คุณจะต้องเปิดใช้การเรียกเก็บเงินใน Cloud Console เพื่อใช้ทรัพยากร Google Cloud

การใช้งาน Codelab นี้น่าจะไม่มีค่าใช้จ่ายใดๆ หากมี ตรวจสอบว่าคุณได้ทำตามวิธีการใน "การล้างข้อมูล" ซึ่งจะแนะนำคุณเกี่ยวกับวิธีปิดทรัพยากรเพื่อไม่ให้มีการเรียกเก็บเงินนอกเหนือจากบทแนะนำนี้ ผู้ใช้ใหม่ของ Google Cloud จะมีสิทธิ์เข้าร่วมโปรแกรมทดลองใช้ฟรี$300 USD

3. สร้างและกำหนดค่าสเปรดชีตใน Google ชีตและเปิดใช้ API

ขั้นแรก ให้สร้างเอกสารชีตใหม่ (ใช้ชีตนี้ของผู้ใช้ทุกคนได้) เมื่อสร้างแล้ว ให้จดจำตัวระบุ จะใช้เป็นตัวแปรสภาพแวดล้อมสำหรับฟังก์ชันที่เราจะเขียน :

dd77d5fc1364ad3e.png

จากคอนโซล GCP ให้เปิดใช้ Google ชีต API ในโปรเจ็กต์ที่สร้างขึ้นใหม่โดยไปที่ "API และบริการ" แล้วคลิก "ไลบรารี API" หัวข้อ :

c64e2e98b8b55f16.png

ใน "IAM และ ผู้ดูแลระบบ" ให้ไปที่ "บัญชีบริการ" และจดบันทึกอีเมลสำหรับบัญชีบริการเริ่มต้นของ App Engine ซึ่งควรอยู่ในรูปแบบ your-project-id@appspot.gserviceaccount.com นอกจากนี้ คุณยังสร้างบัญชีบริการของคุณเองซึ่งมีไว้สำหรับการดำเนินการนี้โดยเฉพาะได้อีกด้วย

6E279d7e07d4febf.png

สุดท้าย เพียงให้สิทธิ์แก้ไขสเปรดชีตแก่บัญชีบริการนี้โดยใช้ "แชร์" ปุ่ม :

c334062465ddf928.png

ซึ่งตอนนี้เราสามารถเขียน Cloud Function และกำหนดค่าเพื่อใช้บัญชีบริการนี้ได้ ไฟล์จะสามารถเขียนลงในเอกสารสเปรดชีตนี้ที่เราเพิ่งสร้างขึ้นมา

4. สร้างที่เก็บข้อมูลของพื้นที่เก็บข้อมูล

ลองสร้างที่เก็บข้อมูลที่ฟังก์ชันระบบคลาวด์ของเราจะตรวจสอบไฟล์ CSV ใหม่

ในคอนโซล ให้ใช้เมนูด้านซ้ายเพื่อไปยัง "พื้นที่เก็บข้อมูล"... :

2ddcb54423979d25.png

... และสร้างที่เก็บข้อมูลใหม่ชื่อ csv2sheet-POSTFIX (แทนที่ POSTFIX ด้วยค่าที่ไม่ซ้ำกัน) โดยตั้งค่าอื่นทั้งหมดเป็นค่าเริ่มต้น :

dd637080ade62e81.png

5. สร้าง Cloud Function

ตอนนี้เราสร้าง Cloud Function ชื่อ csv2sheet ที่จะทริกเกอร์เมื่ออัปโหลดไฟล์ไปยังที่เก็บข้อมูล Cloud Storage ที่เฉพาะเจาะจงได้แล้ว โค้ดจะเขียนใน Node.js 8 ด้วยฟังก์ชัน async โดยใช้ตัวแก้ไขในบรรทัดใน Cloud Console โดยตรง ดังนี้

6ee1a5ce63174ae8.png

ตรวจสอบว่าได้ตั้งค่าทริกเกอร์เป็น "Cloud Storage" และเพื่อปรับชื่อที่เก็บข้อมูลให้ตรงกับชื่อที่คุณสร้างไว้ในขั้นตอนก่อนหน้า

อัปเดตจุดแรกเข้าสำหรับฟังก์ชันที่เราจะเขียนไปยัง csv2sheet ด้วย :

446e7c7c992c2d8a.png

เปลี่ยนเนื้อหาของฟังก์ชันเป็น

  1. ใช้ Cloud Storage API และ Sheets API
  2. ทำเครื่องหมายฟังก์ชัน csv2sheet เป็น async
  3. รับการเก็บรักษา fileName จากข้อมูลเมตาของเหตุการณ์ Cloud Storage และตั้งชื่อสำหรับชีตใหม่ที่เราจะสร้าง :
const {google} = require("googleapis");
const {Storage} = require("@google-cloud/storage")

exports.csv2sheet = async (data, context) => {
  var fileName = data.name;
  // basic check that this is a *.csv file, etc...
  if (!fileName.endsWith(".csv")) {
    console.log("Not a .csv file, ignoring.");
    return;
  }
  // define name of new sheet  
  const sheetName = fileName.slice(0, -4);

  // TODO!
};

การใช้ async ในที่นี้จำเป็นต้องมีเพื่อใช้ await ซึ่งเราจะดูในอีกสักครู่

ตัวเลือกที่สำคัญสองสามตัวเลือกในการสร้างฟังก์ชันนี้ได้แก่ (คลิกลิงก์ "เพิ่มเติม" ที่ด้านล่างของหน้าจอ) :

  • ใช้เมนูแบบเลื่อนลงเพื่อเลือกบัญชีบริการที่กล่าวถึงข้างต้น
  • กำหนดตัวแปรสภาพแวดล้อมชื่อ SPREADSHEET_ID ซึ่งควรตรงกับเอกสารชีตที่สร้างไว้ก่อนหน้านี้ ดังนี้

fd22d1873bcb8c66.png

ขั้นตอนสุดท้ายคือเนื้อหา package.json ที่มี Cloud Storage API และ Google ชีต API เป็นทรัพยากร Dependency 2 อย่างที่เราจะใช้ (ใช้แท็บ PACKAGE.JSON ของเครื่องมือแก้ไขในบรรทัดของคอนโซล)

{
    "name": "csv2sheet",
    "version": "0.0.42",
    "dependencies": {
        "googleapis": "^51.0.0",
        "@google-cloud/storage": "^5.0.1"
    }
}

เมื่อกำหนดค่าทุกอย่างตามที่อธิบายไว้แล้ว ให้คลิก "สร้าง" ได้เลย หลังจากนั้นไม่นานระบบควรสร้างและติดตั้งใช้งานฟังก์ชัน

6. ตั้งค่าการตรวจสอบสิทธิ์และ Sheets API

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

ในเครื่องมือแก้ไขฟังก์ชันของคอนโซล ให้คลิก "แก้ไข" แล้วเพิ่มโค้ดต่อไปนี้ลงในเนื้อหาของฟังก์ชัน csv2sheet :

// block on auth + getting the sheets API object
const auth = await google.auth.getClient({
  scopes: [
    "https://www.googleapis.com/auth/spreadsheets",
    "https://www.googleapis.com/auth/devstorage.read_only"
  ]
});

จากนั้นเราจะสร้างไคลเอ็นต์ Sheets API ดังนี้

const sheetsAPI = google.sheets({version: 'v4', auth});

7. ใช้ Sheets API เพื่อสร้างชีตเปล่า

ด้วยไคลเอ็นต์ Sheets API เราสามารถสร้างชีตใหม่ง่ายๆ ในเอกสาร แต่ก่อนที่จะดำเนินการต่อ ต่อไปนี้เป็นหมายเหตุสั้นๆ เกี่ยวกับคำศัพท์

  • สเปรดชีตเป็นเอกสารจริงและมีการอ้างอิงโดยตัวระบุ (ดังที่กล่าวถึงข้างต้นและมองเห็นได้ใน URL ของเอกสาร)
  • ชีตเป็นแท็บหนึ่งในเอกสาร และสามารถอ้างอิงได้จากชื่อแท็บ (ชื่อแท็บ) หรือตัวระบุที่สร้างขึ้นเมื่อสร้างชีต

ด้วยเหตุนี้ เราจึงขอแนะนำฟังก์ชันที่ใช้ไคลเอ็นต์ Sheets API เพื่อสร้างชีตว่างที่ตำแหน่ง 2 (โดยทั่วไปจะอยู่หลัง "Sheet1") เริ่มต้น ซึ่งมี 26 คอลัมน์ 2,000 แถว โดยแถวแรกถูกตรึงไว้ (เพิ่มลงในฟังก์ชันโดยใช้เครื่องมือแก้ไขในบรรทัด)

function addEmptySheet(sheetsAPI, sheetName) {
  return new Promise((resolve, reject) => {
    const emptySheetParams = {
      spreadsheetId: process.env.SPREADSHEET_ID,
      resource: {
        requests: [
          {
            addSheet: {
              properties: {
                title: sheetName,
                index: 1,
                gridProperties: {
                  rowCount: 2000,
                  columnCount: 26,
                  frozenRowCount: 1
                }
              }
            }
          }
        ]
      }
    };
    sheetsAPI.spreadsheets.batchUpdate( emptySheetParams, function(err, response) {
        if (err) {
          reject("The Sheets API returned an error: " + err);
        } else {
          const sheetId = response.data.replies[0].addSheet.properties.sheetId;
          console.log("Created empty sheet: " + sheetId);
          resolve(sheetId);
        }
      }
    );
  });
}

โปรดทราบว่าเราต้องใช้ตัวแปรสภาพแวดล้อม SPREADSHEET_ID ที่สร้างขึ้นก่อนหน้านี้แทนการฮาร์ดโค้ดการอ้างอิงไปยังสเปรดชีต

เราต้องจำ sheetId สำหรับคำขอเพิ่มเติมที่ส่งไปยังชีตนี้ นอกจากนี้ ชื่อชีตจะต้องไม่ซ้ำกัน และจะสร้างไม่สำเร็จหากมีชีตชื่อ sheetName อยู่แล้ว

ฟังก์ชัน batchUpdate ใน Sheets API เป็นวิธีทั่วไปในการโต้ตอบกับเอกสาร และมีคำอธิบายอยู่ที่นี่

8. อ่านข้อมูลจากไฟล์ CSV สำหรับการจัดเก็บข้อมูล

ตอนนี้เรามีที่ที่จะถ่ายโอนข้อมูลแล้ว เรามาพัฒนาฟังก์ชันระบบคลาวด์เพิ่มเติมในตัวแก้ไขในบรรทัดและใช้ Cloud Storage API เพื่อดึงข้อมูลจริงจากไฟล์ที่อัปโหลดและจัดเก็บไว้ในสตริง

function readCSVContent(sheetsAPI, file, sheetName) {
  return new Promise((resolve, reject) => {
    const storage = new Storage();
    let fileContents = new Buffer('');
    storage.bucket(file.bucket).file(file.name).createReadStream()
    .on('error', function(err) {
      reject('The Storage API returned an error: ' + err);
    })
    .on('data', function(chunk) {
      fileContents = Buffer.concat([fileContents, chunk]);
    })  
    .on('end', function() {
      let content = fileContents.toString('utf8');
      console.log("CSV content read as string : " + content );
      resolve(content);
    });
  });
}

9. ป้อนข้อมูลในชีตที่สร้างใหม่

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

function populateAndStyle(sheetsAPI, theData, sheetId) {
  return new Promise((resolve, reject) => {
    // Using 'batchUpdate' allows for multiple 'requests' to be sent in a single batch.
    // Populate the sheet referenced by its ID with the data received (a CSV string)
    // Style: set first row font size to 11 and to Bold. Exercise left for the reader: resize columns
    const dataAndStyle = {
      spreadsheetId: process.env.SPREADSHEET_ID,
      resource: {
        requests: [
          {
            pasteData: {
              coordinate: {
                sheetId: sheetId,
                rowIndex: 0,
                columnIndex: 0
              },
              data: theData,
              delimiter: ","
            }
          },
          {
            repeatCell: {
              range: {
                sheetId: sheetId,
                startRowIndex: 0,
                endRowIndex: 1
              },
              cell: {
                userEnteredFormat: {
                  textFormat: {
                    fontSize: 11,
                    bold: true
                  }
                }
              },
              fields: "userEnteredFormat(textFormat)"
            }
          }       
        ]
      }
    };
        
    sheetsAPI.spreadsheets.batchUpdate(dataAndStyle, function(err, response) {
      if (err) {
        reject("The Sheets API returned an error: " + err);
      } else {
        console.log(sheetId + " sheet populated with " + theData.length + " rows and column style set.");
        resolve();
      }
    });    
  });
}

โค้ดนี้ควรจะถูกเพิ่มลงในฟังก์ชันระบบคลาวด์ของเรา ซึ่งตอนนี้เสร็จสมบูรณ์ 99%!

บันทึกวิธีการรวมข้อมูลและการจัดรูปแบบเป็น requests หลายรายการไว้ในการเรียกใช้ batchUpdate ของ Sheets API ครั้งเดียว ทำให้การอัปเดตมีประสิทธิผลและมีประสิทธิภาพมากยิ่งขึ้น

และโปรดทราบว่าเรากำหนดช่วงการแก้ไขที่ตรงกับขนาดของชีตที่เราสร้างขึ้น ซึ่งหมายความว่าเนื้อหาที่เกิน 26 คอลัมน์ (ค่า columnCount ที่ใช้เมื่อสร้างชีต) จะล้มเหลวเมื่อใช้โค้ดนี้

หากทุกอย่างเป็นไปด้วยดี คุณสามารถดำเนินการต่อไปนี้

  1. บันทึกฟังก์ชันที่อัปเดตแล้ว
  2. วางไฟล์ CSV ลงในที่เก็บข้อมูล
  3. คุณจะเห็นป๊อปอัปข้อมูลที่เกี่ยวข้องในสเปรดชีตของคุณ

10. นำข้อมูลทุกอย่างมารวมกันแล้วทดสอบความลื่นไหล

การเรียกฟังก์ชันที่เราเพิ่งพูดถึงไปสามารถเรียกใช้เป็นการเรียกที่บล็อกติดต่อกันในฟังก์ชัน csv2sheet เดิมได้ ดังนี้

  const sheetId = await addEmptySheet(sheetsAPI, sheetName);
  const theData = await readCSVContent(sheetsAPI, data, sheetName);
  await populateAndStyle(sheetsAPI, theData, sheetId);

หากคุณต้องการซอร์สโค้ดของฟังก์ชันที่สมบูรณ์ สามารถอยู่ได้ที่นี่ (ซึ่งน่าจะง่ายกว่าถ้าทำทั้งหมดรวมกันเป็นชุดเดียว)

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

1efae021942e64fa.png

ลองอัปโหลดไฟล์หลายๆ ไฟล์ลงในที่เก็บข้อมูลเพื่อดูว่าจะเกิดอะไรขึ้น

11. เท่านี้ก็เรียบร้อย ถึงเวลาทำลายโครงสร้างพื้นฐานแล้ว

พูดเล่นๆ นะ มันไม่มีโครงสร้างพื้นฐานให้ฉีกทิ้ง ทั้งหมดนี้ทำได้แบบ Serverless เลย!

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

12. ขั้นตอนถัดไปคือ

Codelab นี้สรุปขั้นตอนการฟังการอัปโหลดไปยังที่เก็บข้อมูล Cloud Storage ใน Cloud Function เพื่ออัปเดตสเปรดชีตใน Google ชีตโดยใช้ API ที่เหมาะสม

ขั้นตอนการติดตามผลมีดังนี้ :

หากคุณประสบปัญหากับ Codelab นี้ โปรดรายงานปัญหาโดยใช้ลิงก์ที่มุมล่างซ้าย

เรายินดีรับฟังความคิดเห็นของคุณ