-
Notifications
You must be signed in to change notification settings - Fork 1
Datenbank
Aufgrund der einfachen (serverless, client-side) Benutzung und Realtime-Kompatibilität setzt dieses Projekt auf Googles NoSQL Firebase Realtime Database.
Anders als konventionelle Datenbanken, ist diese nicht aus Tabellen, Spalten, Zeilen, usw. aufgebaut, sondern ist letztendlich JSON.
Um den Code besser verstehen zu können, wird in diesem Abschnitt die Struktur der Datenbank erklärt. Dabei werden zur besseren Orientierung die Top-Level-Schlüssel in Klammern erwähnt.
Es werden primär Eintragungen gespeichert (strecken
).
Zur Unterteilung dieser in Schüler, Klassen und Schulen, werden diese separat gespeichert (fahrer
, klassen
, schulen
).
Für ein möglichst schnelles First Meaningful Paint wird die insgesamt gefahrene Strecke nicht berechnet, sondern gesondert aufgeführt (strecke
).
Weiterhin werden Daten gesammelt, die der Benutzererfahrung dienen oder später analysiert werden können.
Um dem Benutzer die Eingabe sich wiederholender Orte zu erleichtern, werden diese, zusammen mit der Häufigkeit der Benutzung, abgespeichert (orte
).
Dann können ihm beispielsweise die drei am häufigsten benutzten Orte jeweils zur Auswahl angezeigt werden.
Außerdem können die Koordinaten einer Strecke gespeichert werden, sofern diese bekannt sind (der Benutzer die Kilometeranzahl nicht direkt eingibt, sondern berechnen lässt). Da allerdings die Antwort des Distance Matrix Service keine Koordinaten beinhaltet, sondern nur die angegebenen Adressen, wird dieses Feld (routen
) momentan nicht benutzt.
Die Datenbank ist unterteilt in zwei grobe "namespaces": "allgemein" und "spezifisch".
Hier werden Werte gespeichert, die sich über mehrere Saisons hinweg entwickeln/verändern.
Saison, deren Startzeit in der Vergangenheit liegt und deren Endzeit entweder nicht gegeben ist oder in der Zukunft liegt.
Saison, die standardmäßig bei der Saisonauswahl ausgewählt wird.
Saison, die zuletzt eingetragen wurde und deren Endzeit nicht in der Vergangenheit liegt. Wie laufend, nur auch schon vor der Saisonstart passiert ist.
Die Zeiten der Saison werden lediglich zur Anzeige der Countdowns genutzt und sollen nicht anderweitig Verwendung finden. Um den Status einer Saison zu erfahren siehe global/saisons/laufend
& global/saisons/aktiv
.
Hier werden Werte gespeichert, die entweder für die aktuelle Saison wichtig sind oder für die Aktive, falls keine Aktuelle vorhanden ist.
(Zeitlich) Eindeutige Schlüssel werden über die JavaScript-API generiert, sodass von mehreren Orten aus gleichzeitig Listen-Einträge konfliktlos eingetragen werden können.
Die hier umgesetzte Denormalisierung der Struktur ist beabsichtigt und Best Practice bei NoSQL.
Zur Query-Optimierung werden in den Sicherheitsregeln der Datenbank einige Felder vorab geindexed.
Alle Längen werden in Metern gespeichert.
Beim Aktualisieren der strecke
, anzahlStrecken
, anzahlFahrer
und angefeuert
-Schlüssel muss Gleichzeitigkeit beachtet werden, sodass diese Werte immer richtig bleiben. Dieses Problem kann entweder durch sog. Transactions oder durch Atomic Server-side Increments gelöst werden.
Countdowns werden allgemein gespeichert (allgemein/saisons/countdowns), damit die entsprechenden functions durch Setzen dieser getriggert werden können. Sobald Start bzw. Ende passiert sind, werden diese in der entsprechenden Saison gespeichert (allgemein/saisons/:saison/zeit), zur evtl. späteren Auswertung.
Die hier benutzten Schlüssel dienen nur zur Veranschaulichung und sehen eigentlich anders aus.
x
dient als Platzhalter für eine Zahl.
{
"allgemein": {
"strecke": x,
"anzahlStrecken": x,
"anzahlFahrer": x,
"saisons": {
"aktiv": "2021",
"laufend": "2021",
"aktuell": "2021",
"anzahl": x,
"anzahlHistorisch": x,
"countdowns": {
"start": x,
"ende": x
},
"liste": {
"2021": true
},
"details": {
"2021": {
"zeit": {
"start": x,
"ende": x
},
"runden": x,
"strecke": x,
"anzahlStrecken": x,
"anzahlFahrer": x,
"schulen": {
"liste": {
"Gymnasium Höchstadt": true
},
"details": {
"Gymnasium Höchstadt": {
"strecke": x,
"anzahlStrecken": x,
"anzahlFahrer": x,
"potAnzahlFahrer": x,
"angefeuert": x
}
}
}
}
}
},
"schulen": {
"liste": {
"Gymnasium Höchstadt": true
},
"details": {
"Gymnasium Höchstadt": {
"saisons": {
"liste": {
"2021": true
}
}
}
}
}
},
"spezifisch": {
"klassen": {
"leer": false,
"liste": {
"Gymnasium Höchstadt": {
"9D": true
}
},
"details": {
"Gymnasium Höchstadt": {
"9D": {
"strecke": x,
"anzahlStrecken": x,
"anzahlFahrer": x,
"potAnzahlFahrer": x,
"email": "schmidt@gy-ho.de",
"uid": "XA-32A98fAga-",
"fahrer": {
"Leonard Nolting": "fahrerEins"
}
}
}
}
},
"fahrer": {
"fahrerEins": {
"schule": "Gymnasium Höchstadt",
"klasse": "klasseEins",
"name": "Leonard Nolting",
"strecke": x,
"anzahlStrecken": x
}
},
"strecken": {
"streckeEins": {
"fahrer": "fahrerEins",
"strecke": x,
"zeitpunkt": x
}
},
"routen": {
"streckeEins": {
"von": {
"ort": "Am Hopfengarten 5",
"lat": x,
"lng": x
},
"zu": {
"ort": "Gymnasium Höchstadt a. d. Aisch",
"lat": x,
"lng": x
}
}
},
"orte": {
"fahrerEins": {
"Gymnasium Höchstadt a. d. Aisch": 5,
"Am Hopfengarten 5": 3,
"Eiffelturm": 1,
"Eisdiele Höchstadt": 1
}
}
}
}