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.
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 :
2. Konfiguracja i wymagania
Samodzielne konfigurowanie środowiska
- 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ć.
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
.
- 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 :
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”. :
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.
Na koniec przyznaj temu kontu usługi uprawnienia do edycji arkusza kalkulacyjnego za pomocą przycisku „Udostępnij” przycisk :
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... :
... i utwórz nowy zasobnik o nazwie csv2sheet-POSTFIX
(zastąp POSTFIX unikalnym elementem) z pozostałymi ustawieniami ustawionymi na wartości domyślne :
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 :
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
:
Teraz zmień treść funkcji na :
- korzystać z interfejsów Cloud Storage i Arkuszy API
- oznacz funkcję
csv2sheet
jakoasync
- 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 :
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:
- zapisz zaktualizowaną funkcję
- Upuść plik CSV do zasobnika
- 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.
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 :
- Zapoznaj się z instrukcjami dotyczącymi Cloud Functions (zawiera też kilka sprawdzonych metod).
- Zapoznaj się z jednym z samouczków dotyczących Cloud Functions.
- Dowiedz się więcej o interfejsie API Arkuszy Google
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.