Een firestore database is een NoSQL database gebaseerd op collections en documents.
De data is opgebouwd als objecten met key-value paren.
Doumenten worden samen gebracht in collections en kunnen op zich ook collections hebben als sub-collecten met weerom documenten.
Het path naar een specfiek document bestaat dus steeds uit een alwisseling collection/document/collection/document...
Queries lopen op collections en gebruiken de veldvoorwaarden van een document.
Queries kunnen ook gebeuren op complexere velden, zoals array's.
Er bestaan een Native Firestore, wat de nieuwste vorm is en een Datastore Firestore, welke een backward compatiple versie is met de vroegere Cloud datastore.
Deze laatste wordt niet meer aangeraden voor nieuwe projecten.
Meer uitleg kan je vinden op Cloud Firestore
Om kunnen gebruik te maken van Firestore binnen Apps script kan je de volgende lib integreren.
1VUSl4b1r1eoNcRWotZM3e87ygkxvXltOgyDZhixqncz9lQ3MjfT1iKFw
De procedure vind je op: A Quick and Dirty Way to Connect Firestore to Google Sheets
Voor het toegankelijk kunnen maken van een Firestore heb je een Serviceaccount nodig, iets wat enkel door een Admin in je domain kan aangemaakt worden.
De volgende Github wiki bevat de API calls mogelijk met voorgaande API
https://github.com/grahamearley/FirestoreGoogleAppsScript/wiki/Firestore-Method-Documentation
Er zijn verschillende wegen om een Firestore aan te maken, maar niet alle wegen geven hetzelfde resultaat.
De weg die te verkiezen valt is deze via FireBase, een ontwikkelomgeving om de Firestore te gebruiken, samen met Apps op IOS/Android/web.
Open Firebase console
Maak een nieuw project aan en koppel het niet aan een bestaand GCP project, omdat je dan automatisch in de Firestore Datastore mode terecht komt en wij gaan voor de Firestore Native mode.
Koppel dit aan je domain cloud project waarin billing op staat.
Koppel het geheel ook aan een Google Analytics account.
Je komt nu standaard in een Spark betaalplan terecht, dit is de laagste vorm.
Via de settings menu kan je verschillende instellingen en gegevens bekomen van je project
Voor het toegankelijk kunnen maken van een Firestore heb je een Serviceaccount nodig, iets wat enkel door een Admin in je domain kan aangemaakt worden.
Het service account heb je nodig om de toegang te regelen tot de data vanuit de verschillende onderdelen.
Dit kan je terug vinden in de serviceaccount tab.
Je hebt de volgende gegevens nodig uit de API key om je app te kunnen laten communiceren met Firebase.
email, private-key, firebase-product-id
Het genereren van de key kan vanuit de firebase console, je hoeft niet via de Cloud console te gaan.
Er wordt je een JSON file gedownload die je nodig hebt om de app lib te laten werken.
Bewaar deze op een private schijft, waarop enkel de ontwikkelaar/configurator van de app toegang heeft.
Als controle kan je in de cloudconsole kijken of het service account is aangemaakt.
Meestal draagt het service account de naam van het project, zoniet pas je de naam aan zodat een duidelijk verband zichtbaar wordt.
Om de API service te kunnen gebruiken moet de API voor dit project worden geactiveerd in de cloudconsole.
Hiervoor ga je naar console.cloud.google.com
Kies bovenaan je projectnaam
Ga nu in de menu naar de optie Firestore.
Op de volgende pagina enable je de API en krijg je na het enabled het volgende te zien
Wanneer je bij code in je programma de volgende melding krijgt, wil dit zeggen dat je de FirestoreAPI nog niet geactiveerd hebt voor dit project in de Cloud console.
Je kan hiervoor de aangeboden link gebruiken om rechtstreeks naar de pagina te gaan.
In je project moet je de datastore nog aanmaken, zodat de key erop kan toegrijpen.
Je krijgt nu de keuze om een native of datastore aan te maken.
Wij kiezen voor een Native mode versie van Firestore en om de data te bewaren in Europa.
Klik daarna op Create Database
Hierna krijg je een scherm waar je vanuit de cloud console data kan aanmaken of invullen in je DB.
Heb je dit vergeten dan krijg je bij het uitvoeren van je code in Apps script, de volgende error melding en kan je via de link de aanmaak doen.
Vanaf dit moment kan je gebruik maken van de Firestore in native mode en Documents/collections en queries gaan uitvoeren.
Je kan je Firestore DB via twee wegen benaderen om acties op te ondernemen:
via de Firebase console
of via de Cloud console.
In beide gevallen moet je het GCP project selecteren waarin de Firestore is aangemaakt.
Hiervoor maken we gebruik van voorgaande FirestoreApp library
Zoals voorheen reeds aangehaald zal Apps Script je met de nodige linken voorzien, wanneer je een service aanroept binnen Firestore die nog niet geactiveerd is.
Met de volgende code kan je een test doen.
Het opzet is om de JSON key file op een prive of beperkt toegankelijke drive te plaatsen en de app de link naar deze file door te geven.
De apps script code gaat de gegevens uit deze file lezen en gebruiken, de firestore code wordt zo niet "hardware matige" in de script code geplaatst, waardoor de code vrij kan versprijd worden.
Hierdoor wordt het bekomen van de Firestore key enkel mogelijk indien de eigenaar van de DB je de toegang tot de keyfile geeft en kan de app universeel gemaakt worden zodat ze voor verschillende DB kan gebruikt worden.
De code die we hier weergeven zorgt ervoor dat zulke werking kan gebeuren.
Laad de JSON key file op in een beperkt toegankelijke gdrive (shared drive, waar je eventueel ook de source code van je app bewaart)
De eerste test die je doet vanuit je app script is de toegang tot de db testen.
In de volgende code vul je de gegevens in die je verkregen hebt en vervat zitten in de key JSON file die je gegenereerd hebt bij het aanmaken van de Firestore Service account.
Indien de definities niet correct zijn verlopen zal je bij het debuggen de nodige error meldingen krijgen, zoals bovenaan getoond en kan je de acties uitvoeren.
Je kan dus ook starten met het Apps script en als reactie op de error codes de settings aanpassen, iets wat verder terug komt in de werking.
/**
* Access to Firestore db hardcoded with Serviceaccount *
* @return {object} object to firestore db
*/
function getFireStore() {
try {
const config = {
'project_id': 'firestornative',
'private_key': '-----BEGIN PRIVATE KEY-----\nMIIEvgI…cjgAYZ\n-----END PRIVATE KEY-----\n',
'client_email': 'firebase-adminsdk-i5cfz@firestornative.iam.gserviceaccount.com',
}
var firestore = FirestoreApp.getFirestore(config.client_email, config.private_key, config.project_id);
return firestore
} catch (e) {
console.log(e);
}
}
Deze code NOOIT in je publiek beschikbare source laten staan, daar men op deze wijze toegang krijgt tot de DB.
Bij deze methode zijn de keys leesbaar in het script, maar er is een mogelijkheid om de key value’s te binden in de properties van het script, waardoor deze niet meer leesbaar zijn.
De script maker (not container bound script) moet een tool gebruiken om de properties te zetten, waarna een app kan gebruikt worden.
Info kan je vinden op deze vraag: #62 en de google properties service, alsook Storing API ckeys in apps script
Het volgende principe wordt toegepast om een container bound script toe te laten dat je manueel kopieert, maar waarbij je de toegang tot de DB beperkt door het separaat doorgeven van een URL naar een file, waarin de key code zit.
Zo kan je de toegang tot de db beperken tot bepaalde personen, die scripts mogen runnen en die je de file link gedeeld hebt.
Iemand die het script kopieert heeft zo niet de key tot je db en wie je de rechten wil afnemen, geef je geen toegang meer tot je key file.
Na het aanmaken van de volgende script code doe je een reload van de sheet.
Voer de code setKeyFile() in debug uit:
Je zal nu een vraag krijgen om de URL van de keyfile in te vullen eventueel voorafgegaan door een aantal vragen over rechten toelaten etc.
Dit is de gedeelde link van de key file.
Eens je deze url hebt doorgegeven, blijft deze bewaard in de script properies en is het niet meer nodig, zolang dit schript gekoppeld blijft aan deze sheet, om de actie te herhalen.
Voer nu de functie test1() uit in debug mode.
Als alle goed verlopen is, zal je geen error meldingen bekomen.
Nu weet je dat het service account, de services en de API koppelingen allemaal werken en kan je verder met het maken van je code voor de add-on of app.
Denk eraan, deze toegang is een server-server toegang naar de Firestore en heeft daardoor geen beperking op de toegang en overruled ook alle security settings voor clients in Firebase!
Je hebt deze code nodig omdat Apps script geen andere vorm toelaat.
Wil je gebruik kunnen maken van de client access, dien je gebruik te maken van de REST of andere API's van Firebase.
In onze situatie is dit niet nodig, door het gebruik binnen het domain en doordat de toegang tot de key file beperkt wordt.
De Firestore API key file kan je uploaden naar een Gdrive en op deze file kunnen de deelrechten per user worden ingesteld.
In het Container bound script, voorzie je een menu waarmee je de URL van deze file kan inlezen.
function setKeyFile(){
var ui = SpreadsheetApp.getUi();
var userProperties = PropertiesService.getUserProperties();
//const Key_file = 'api.key';
var scriptValue = ui.prompt('Please provide your Private key.' , ui.ButtonSet.OK);
userProperties.setProperty('Key_file', scriptValue.getResponseText());
}
Via een read json file kan je de keys toekennen aan de script properties van een script in een container script.
/**
* Get file ID from URL
*@param{string} url of file
*@return {string} file ID
*/
function getFileIdFromDriveUrl(url) {
var match = url.match(/([a-z0-9_-]{25,})[$/&?]/i);
return match ? match[1] : null;
}
function readKeyFile(fileURL) {
Try{
var files = DriveApp.getFileById(getFileIdFromDriveUrl(fileURL));
var content = files.getBlob().getDataAsString();
var json = JSON.parse(content);
//setdata(json);
let docProperties = PropertiesService.getDocumentProperties();
docProperties.setProperty('project_id', json.project_id);
docProperties.setProperty('private_key', json.private_key);
docProperties.setProperty('client_email', json.client_email);
return true
} catch (e) {
var ui = SpreadsheetApp.getUi();
ui.alert(e)
return false
Logger.log(e);
}
}
In de connectie functies van FireStore gebruik je enkel de script properties.
function getFireStore() {
try {
const docProperties = PropertiesService.getDocumentProperties();
const config = {
'project_id': docProperties.getProperty('project_id'),
'private_key': docProperties.getProperty('private_key'),
'client_email': docProperties.getProperty('client_email')
}
var firestore = FirestoreApp.getFirestore(config.client_email, config.private_key, config.project_id);
return firestore
} catch (e) {
var ui = SpreadsheetApp.getUi();
ui.alert(e)
Logger.log(e);
}
}
function test1(){
let userProperties =PropertiesService.getUserProperties();
let read= readKeyFile(userProperties.getProperty('Key_file'))
let firestore = getFireStore()
let documents = firestore.getDocuments("/")
}