Cloud Function برای خودکارسازی واردات داده CSV به Google Sheets

1. مقدمه

هدف این نرم افزار کد این است که بفهمید چگونه یک تابع ابری بنویسید تا به آپلود فایل CSV در فضای ذخیره سازی ابری واکنش نشان دهید، محتوای آن را بخوانید و از آن برای به روز رسانی یک برگه Google با استفاده از Sheets API استفاده کنید.

e9c78061022a6760.png

این را می توان به عنوان اتوماسیون یک مرحله دستی "وارد کردن به عنوان CSV" در نظر گرفت. این اطمینان حاصل می کند که می توانید داده ها (شاید توسط تیم دیگری تولید شده است) را در یک صفحه گسترده به محض در دسترس بودن تجزیه و تحلیل کنید.

این چیزی است که پیاده سازی به نظر می رسد:

52df703605ae4bd3.png

2. راه اندازی و الزامات

تنظیم محیط خود به خود

  1. به کنسول Cloud وارد شوید و یک پروژه جدید ایجاد کنید یا از یک موجود استفاده مجدد کنید. (اگر قبلاً یک حساب Gmail یا G Suite ندارید، باید یک حساب ایجاد کنید .)

dMbN6g9RawQj_VXCSYpdYncY-DbaRzr2GbnwoV7jFf1u3avxJtmGPmKpMYgiaMH-qu80a_NJ9p2IIXFppYk8x3wyymZXavjglNLJJHHXieCvXw5 Zw

ci9Oe6PgnbNuSYlMyvbXF1JdQyiHoEgnhl4PlV_MFagm2ppzhueRkqX4eLjJllZco_2zCp0V0bpTupUSKji9KkQyWqj11pqit1K1faS1V6aTQz5GpG0T

8-tA_Lheyo8SscAVKrGii2coplQp2_D1Iosb2ViABY0UUO1A8cimXUu6Wf1R9zJIRExL5OB2j946aIiFtyKTzxDcNnuznmR45vZ2HMoK3UUO1A8cimXUu6Wf1R9zJIRExL5OB2j946aIiFtyKTzxDcNnuznmR45vZ2HMoK3UUUO1A8cimXUu6Wf1R9zJIRExL5OB2j946aIiFtyKTzxDcNnuznmR45vZ2HMoK3UUUO1A8CXUF

شناسه پروژه را به خاطر بسپارید، یک نام منحصر به فرد در تمام پروژه های Google Cloud (نام بالا قبلاً گرفته شده است و برای شما کار نخواهد کرد، متأسفیم!). بعداً در این آزمایشگاه کد به عنوان PROJECT_ID نامیده خواهد شد.

  1. در مرحله بعد، برای استفاده از منابع Google Cloud، باید صورت‌حساب را در Cloud Console فعال کنید .

اجرا کردن از طریق این کد لبه نباید هزینه زیادی داشته باشد، اگر اصلاً باشد. حتماً دستورالعمل‌های موجود در بخش «تمیز کردن» را دنبال کنید که به شما توصیه می‌کند چگونه منابع را خاموش کنید تا بیش از این آموزش متحمل صورت‌حساب نشوید. کاربران جدید Google Cloud واجد شرایط برنامه آزمایشی رایگان 300 دلاری هستند.

3. یک Google Sheet ایجاد و پیکربندی کنید و API را فعال کنید

ابتدا اجازه دهید یک سند Sheets جدید ایجاد کنیم (این برگه می تواند متعلق به هر کاربری باشد). پس از ایجاد، شناسه آن را به خاطر بسپارید. به عنوان یک متغیر محیطی برای تابعی که می نویسیم استفاده می شود:

dd77d5fc1364ad3e.png

از کنسول GCP ، با رفتن به بخش «APIs and Services» و سپس «API Library»، API کاربرگ‌نگار Google را در پروژه تازه ایجاد شده خود فعال کنید:

c64e2e98b8b55f16.png

در بخش «IAM & admin»، به «حساب‌های خدمات» بروید و ایمیل حساب سرویس پیش‌فرض App Engine را یادداشت کنید. باید به شکل your-project-id@appspot.gserviceaccount.com باشد. البته شما همچنین می توانید حساب سرویس خود را که به این عمل اختصاص داده شده است ایجاد کنید.

6e279d7e07d4febf.png

در نهایت، به سادگی با استفاده از دکمه «اشتراک‌گذاری»، به صفحه‌گسترده خود امتیاز ویرایش حساب کاربری را بدهید:

c334062465ddf928.png

با این تنظیمات، اکنون می‌توانیم تابع Cloud خود را بنویسیم و آن را برای استفاده از این حساب سرویس پیکربندی کنیم. می‌تواند در این سند صفحه‌گسترده که به تازگی ایجاد کرده‌ایم بنویسد.

4. یک سطل ذخیره سازی ایجاد کنید

بیایید سطلی را ایجاد کنیم که عملکرد ابری ما برای فایل‌های CSV جدید نظارت می‌کند.

در کنسول، از منوی سمت چپ برای پیمایش به "Storage" استفاده کنید... :

2ddcb54423979d25.png

... و یک سطل جدید به نام csv2sheet-POSTFIX ایجاد کنید (POSTFIX را با چیزی منحصربفرد جایگزین کنید) با سایر تنظیمات که روی مقادیر پیش فرض تنظیم شده اند:

dd637080ade62e81.png

5. عملکرد Cloud را ایجاد کنید

اکنون می‌توانیم یک تابع Cloud به نام csv2sheet ایجاد کنیم که در آپلود فایل‌ها در یک سطل ذخیره‌سازی ابری خاص فعال می‌شود. کد در Node.js 8 با توابع async با استفاده از ویرایشگر درون خطی مستقیماً در Cloud Console نوشته می‌شود:

6ee1a5ce63174ae8.png

مطمئن شوید که Trigger را روی "Cloud Storage" تنظیم کرده اید و نام سطل را با نامی که در مرحله قبل ایجاد کرده اید تنظیم کنید.

همچنین نقطه ورودی را برای تابعی که می خواهیم در csv2sheet بنویسیم به روز کنید:

446e7c7c992c2d8a.png

حالا بدنه تابع را به زیر تغییر دهید:

  1. از Cloud Storage و 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 با APIهای Cloud Storage و Google Sheet به‌عنوان دو وابستگی است که استفاده می‌کنیم (از تب PACKAGE.JSON ویرایشگر داخلی کنسول استفاده کنید):

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

هنگامی که همه چیز را همانطور که توضیح داده شد پیکربندی کردید، ادامه دهید، روی "ایجاد" کلیک کنید! پس از یک دقیقه کوتاه تابع شما باید ایجاد و مستقر شود.

6. auth و Sheets API را راه اندازی کنید

قبل از اینکه با استفاده از ویرایشگر درون خطی، کد دیگری را در تابع Cloud خود بنویسیم، باید ایجاد یک Google Client API با دامنه‌های Storage و Sheet مناسب را مسدود کنیم (به یاد داشته باشید، این بخشی از یک تابع async است).

در ویرایشگر تابع کنسول، روی "EDIT" کلیک کنید و کد زیر را به بدنه تابع 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 ستون، 2000 ردیف، با سطر اول ثابت شده است (آن را با استفاده از آن به تابع خود اضافه کنید. ویرایشگر درون خطی):

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 مشتری Sheet ایجاد کرده ایم و داده هایی که به تازگی جمع آوری کرده ایم، پر کنیم. از این فرصت استفاده می‌کنیم و به ستون‌های برگه نیز سبک اضافه می‌کنیم (تغییر اندازه قلم ردیف بالا و پررنگ کردن آن):

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();
      }
    });    
  });
}

این کد باید به عملکرد Cloud ما اضافه شود که اکنون 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. همین! زمان تخریب زیرساخت ها است

شوخی دارم، هیچ زیرساختی برای خراب کردن وجود ندارد، این همه بدون سرور انجام شد!

در صورت تمایل می توانید تابع ابر و سطلی را که ایجاد کرده اید یا حتی کل پروژه را حذف کنید.

12. بعد چی؟

این به پایان می‌رسد که این لبه کد شما را از طریق مراحل گوش دادن به آپلودهای یک سطل فضای ذخیره‌سازی ابری در یک تابع ابری برای به‌روزرسانی یک برگه Google با استفاده از API مناسب راهنمایی می‌کند.

در اینجا چند مرحله پیگیری وجود دارد:

اگر با این کد لبه با مشکل مواجه شدید، با استفاده از پیوند در گوشه سمت چپ پایین، هر مشکلی را گزارش دهید.

بازخورد شما قابل تقدیر است!