Funkcja w Cloud Functions umożliwiająca automatyzację importowania danych z pliku CSV do Arkuszy Google

1. Wprowadzenie

Dzięki temu ćwiczeniu w Codelabs dowiesz się, jak napisać funkcję w Cloud Functions, która zareaguje na plik CSV przesłany do Cloud Storage, oraz odczytać jego zawartość i wykorzystać ją do aktualizowania arkusza Google za pomocą interfejsu Sheets API.

e9c78061022a6760.png

Można to utożsamiać z automatyzacją ręcznego „importowania pliku CSV”. krok po kroku. Dzięki temu będziesz mieć możliwość przeanalizowania danych (na przykład przygotowanych przez inny zespół) w arkuszu kalkulacyjnym, gdy tylko będą dostępne.

Implementacja wygląda tak :

52df703605ae4bd3.png

2. Konfiguracja i wymagania

Samodzielne konfigurowanie środowiska

  1. Zaloguj się w konsoli Google Cloud i utwórz nowy projekt lub wykorzystaj już istniejący. Jeśli nie masz jeszcze konta Gmail lub G Suite, musisz je utworzyć.

dMbN6g9RawQj_VXCSYpdYncY-DbaRzr2GbnwoV7jFf1u3avxJtmGPmKpMYgiaMH-qu80a_NJ9p2IIXFppYk8x3wyymZXavjglNLJJhuXieCem56H30hwXtd8PvXGpXJO9gEUDu3cZw

ci9Oe6PgnbNuSYlMyvbXF1JdQyiHoEgnhl4PlV_MFagm2ppzhueRkqX4eLjJllZco_2zCp0V0bpTupUSKji9KkQyWqj11pqit1K1faS1V6aFxLGQdkuzGp4rsQTan7F01iePL5DtqQ

8-tA_Lheyo8SscAVKrGii2coplQp2_D1Iosb2ViABY0UUO1A8cimXUu6Wf1R9zJIRExL5OB2j946aIiFtyKTzxDcNnuznmR45vZ2HMoK3o67jxuoUJCAnqvEX6NgPGFjCVNgASc-lg

Zapamiętaj identyfikator projektu, unikalną nazwę we wszystkich projektach Google Cloud (powyższa nazwa jest już zajęta i nie będzie Ci odpowiadać). W dalszej części tego ćwiczenia w Codelabs będzie ona określana jako PROJECT_ID.

  1. Następnie musisz włączyć płatności w Cloud Console, aby korzystać z zasobów Google Cloud.

Ukończenie tego ćwiczenia z programowania nie powinno kosztować zbyt wiele. Postępuj zgodnie z instrukcjami podanymi w sekcji „Czyszczenie” W tym samouczku znajdziesz wskazówki, jak wyłączyć zasoby, aby uniknąć naliczania opłat. Nowi użytkownicy Google Cloud mogą skorzystać z programu bezpłatnego okresu próbnego o wartości 300 USD.

3. Tworzenie i konfigurowanie Arkuszy Google oraz włączanie interfejsu API

Najpierw utwórzmy nowy dokument w Arkuszach (ten arkusz może należeć do dowolnego użytkownika). Po utworzeniu zapamiętuj jego identyfikator. zostanie użyty jako zmienna środowiskowa dla funkcji, którą zapiszemy :

dd77d5fc1364ad3e.png

W konsoli GCP otwórz „Interfejsy API i usługi” i włącz w swoim nowo utworzonym projekcie interfejs Arkuszy Google API. a następnie „Biblioteka interfejsów API”. :

c64e2e98b8b55f16.png

W sekcji „Uprawnienia i admin” i wybierz „Konta usługi”. i zwróć uwagę na adres e-mail domyślnego konta usługi App Engine. Powinien mieć format your-project-id@appspot.gserviceaccount.com. Możesz też utworzyć własne konto usługi przeznaczone do tego działania.

6e279d7e07d4febf.png

Na koniec przyznaj temu kontu usługi uprawnienia do edycji arkusza kalkulacyjnego za pomocą przycisku „Udostępnij” przycisk :

c334062465ddf928.png

Dzięki tej konfiguracji możemy teraz zapisać funkcję w Cloud Functions i skonfigurować ją tak, aby korzystała z tego konta usługi. Będzie mogła zapisywać dane w utworzonym właśnie arkuszu kalkulacyjnym.

4. Utwórz zasobnik na dane

Utwórzmy zasobnik, który będzie monitorowany przez naszą funkcję w Cloud Functions pod kątem nowych plików CSV.

W konsoli otwórz „Miejsce na dane” w menu po lewej stronie... :

2ddcb54423979d25.png

... i utwórz nowy zasobnik o nazwie csv2sheet-POSTFIX (zastąp POSTFIX unikalnym elementem) z pozostałymi ustawieniami ustawionymi na wartości domyślne :

dd637080ade62e81.png

5. Tworzenie funkcji w Cloud Functions

Możemy teraz utworzyć funkcję w Cloud Functions o nazwie csv2sheet, która będzie aktywowana podczas przesyłania plików do określonego zasobnika Cloud Storage. Kod zostanie napisany w Node.js 8 z funkcjami asynchronicznymi za pomocą wbudowanego edytora bezpośrednio w Cloud Console :

6ee1a5ce63174ae8.png

Pamiętaj, aby ustawić aktywator na „Cloud Storage” i dostosować nazwę zasobnika do tej, która została utworzona w poprzednim kroku.

Zaktualizuj również punkt wejścia funkcji, którą zapiszemy w csv2sheet :

446e7c7c992c2d8a.png

Teraz zmień treść funkcji na :

  1. korzystać z interfejsów Cloud Storage i Arkuszy API
  2. oznacz funkcję csv2sheet jako async
  3. pobierz fileName z metadanych zdarzenia w Cloud Storage i pobierz nazwę nowego arkusza, który utworzymy :
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!
};

Aby możliwe było użycie elementu await, atrybut async jest wymagany, jak za chwilę zobaczymy.

Oto kilka ważnych opcji tworzenia tej funkcji (kliknij link „Więcej” u dołu ekranu) :

  • Z menu wybierz konto usługi omówione powyżej.
  • Zdefiniuj zmienną środowiskową o nazwie SPREADSHEET_ID, która powinna pasować do utworzonego wcześniej dokumentu arkusza :

fd22d1873bcb8c66.png

Na ostatnim etapie konfiguracji oto treść package.json z interfejsami API Cloud Storage i Arkuszy Google, które użyjemy w formie 2 zależności (użyj wbudowanego edytora PACKAGE.JSON) w konsoli:

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

Po skonfigurowaniu wszystkich zgodnie z opisem kliknij „Utwórz” ! Po krótkiej minucie funkcja powinna zostać utworzona i wdrożona.

6. Skonfiguruj uwierzytelnianie i interfejs Arkuszy API

Zanim napiszemy kolejny kod w funkcji Cloud Functions za pomocą edytora wbudowanego, musimy zablokować tworzenie interfejsu API klienta Google z odpowiednimi zakresami Cloud Storage i Sheet (pamiętaj, że jest to część funkcji async).

W edytorze funkcji konsoli kliknij „EDYTUJ”. i dodaj ten kod do treści funkcji 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"
  ]
});

Następnie możemy utworzyć klienta interfejsu API Arkuszy Google :

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

7. Tworzenie pustego arkusza za pomocą interfejsu Arkusze API

Za pomocą klienta interfejsu API Arkuszy Google możemy utworzyć prosty nowy arkusz w dokumencie, ale zanim przejdziemy dalej, oto krótka uwaga na temat słownictwa:

  • arkusz kalkulacyjny jest rzeczywistym dokumentem, do którego odwołuje się jego identyfikator (omówione powyżej i widoczne w adresie URL dokumentu);
  • arkusz jest jedną z kart w dokumencie. Przy użyciu nazwy (nazwy karty) lub identyfikatora wygenerowanego podczas tworzenia arkusza może się do niego odwoływać.

Mając to na uwadze, oto funkcja korzystająca z klienta interfejsu API Arkuszy do tworzenia pustego arkusza na pozycji 2 (zwykle po domyślnym arkuszu „Sheet1”) z 26 kolumnami, 2000 wierszami i zablokowanym pierwszym wierszem (dodaj tę funkcję do funkcji za pomocą edytora wbudowanego) :

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

Zwróć uwagę, że zamiast umieszczać na stałe odwołanie do arkusza kalkulacyjnego, polegamy na utworzonej wcześniej zmiennej środowiskowej SPREADSHEET_ID.

Musimy zapamiętać sheetId w przypadku kolejnych żądań dotyczących tego konkretnego arkusza. Oprócz tego nazwa arkusza musi być unikalna. Tworzenie arkusza się nie uda, jeśli istnieje już arkusz o nazwie sheetName.

Funkcja batchUpdate w interfejsie Arkuszy API jest typowym sposobem interakcji z dokumentami i została opisana tutaj.

8. Odczytywanie danych z pliku CSV używanego do przechowywania danych

Skoro mamy już miejsce na pobranie danych, czas rozwinąć funkcję w Cloud Functions we wbudowanym edytorze oraz użyć interfejsu Cloud Storage API, aby pobrać rzeczywiste dane z przesłanego właśnie pliku i zapisać je w ciągu znaków:

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. Wypełnij nowo utworzony arkusz

Czas wypełnić arkusz, który utworzyliśmy przy użyciu tego samego interfejsu API klienta Arkuszy, i uzupełnić dane, które właśnie zebraliśmy. Skorzystamy też z okazji, by dodać styl do kolumn arkusza (zmienimy rozmiar czcionki w górnym wierszu i pogrubimy go) :

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

Ten kod należy dodać do naszej funkcji w Cloud Functions, która jest już gotowa w 99%.

Zwróć uwagę, że dane i styl są łączone w ramach kilku funkcji requests w jednym wywołaniu batchUpdate interfejsu Arkuszy API. Pozwala to uzyskać bardziej wydajną i indywidualną aktualizację.

Należy również pamiętać, że definiujemy zakres edycji odpowiadający rozmiarowi utworzonego przez nas arkusza. Oznacza to, że w przypadku treści większej niż 26 kolumn (wartość columnCount używana podczas tworzenia arkusza) nie będzie można użyć tego konkretnego kodu.

Jeśli wszystko pójdzie dobrze, możesz wykonać te czynności:

  1. zapisz zaktualizowaną funkcję
  2. Upuść plik CSV do zasobnika
  3. wyświetli się odpowiednie dane w arkuszu kalkulacyjnym.

10. Połączenie wszystkich elementów i testowanie przepływu

Wywołania funkcji, które przed chwilą omówiliśmy, można wykonywać jako kolejne wywołania blokujące w pierwotnej funkcji csv2sheet:

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

Jeśli potrzebujesz pełnego kodu źródłowego funkcji, znajdziesz go tutaj (prawdopodobnie łatwiej będzie go zebrać w jednym zestawie).

Gdy wszystko będzie gotowe, wystarczy przesłać plik CSV do odpowiedniego zasobnika i zobaczyć, jak arkusz kalkulacyjny zostanie zaktualizowany o nowy arkusz z zawartością pliku. Oto przykładowy plik CSV, jeśli jeszcze go nie masz.

1efae021942e64fa.png

Spróbuj przesłać kilka plików do zasobnika i zobacz, co się stanie.

11. Znakomicie. Czas zniszczyć infrastrukturę

Żartuję, nie ma infrastruktury do roszczenia. Wszystko odbywa się bez serwera.

W razie potrzeby możesz usunąć funkcję w Cloud Functions i utworzony zasobnik, a nawet cały projekt.

12. Co dalej?

To już koniec tego ćwiczenia w programie. W ten sposób dowiesz się, jak za pomocą funkcji w Cloud Functions nasłuchiwać przesyłanie danych do zasobnika Cloud Storage w celu zaktualizowania arkusza Google przy użyciu odpowiedniego interfejsu API.

Więcej propozycji :

Jeśli podczas ćwiczeń w programie wystąpiły jakieś problemy, możesz je zgłosić, korzystając z linku w lewym dolnym rogu.

Twoja opinia jest dla nas bardzo ważna.