UPDATE: Es gibt jetzt eine doc on structuring data. Siehe auch diesen ausgezeichneten Beitrag auf NoSQL data structures.
Das Hauptproblem mit hierarchischen Daten, im Gegensatz zu RDBMS, ist, dass es verlockend ist, Daten zu verschachteln, weil wir es können. Im Allgemeinen möchten Sie Daten trotz der fehlenden Join-Anweisungen und Abfragen einigermaßen normalisieren (genau wie bei SQL).
Sie möchten auch denormalize an Orten, an denen Leseeffizienz ein Anliegen ist. Dies ist eine Technik, die von allen großen Apps (z. B. Twitter und Facebook) verwendet wird und obwohl es gegen unsere DRY-Prinzipien verstößt, ist es im Allgemeinen ein notwendiges Merkmal von skalierbaren Apps.
Das Wesentliche hier ist, dass Sie hart an Schreibarbeiten arbeiten wollen, um das Lesen einfach zu machen. Halten Sie logische Komponenten, die separat gelesen werden, separat (z. B. für Chatrooms, stellen Sie die Nachrichten, Meta-Informationen zu den Räumen und Listen von Mitgliedern nicht alle an derselben Stelle, wenn Sie die Gruppen später iterieren möchten).
Der primäre Unterschied zwischen Firebase-Echtzeitdaten und einer SQL-Umgebung besteht in der Abfrage von Daten. Es gibt keine einfache Möglichkeit, "SELECT USERS WHERE X = Y" zu sagen, aufgrund der Echtzeit-Natur der Daten (es ändert sich ständig, sharding, reconciling usw.), was ein einfacheres internes Modell erfordert, um die synchronisierten Clients in Schach zu halten)
ein einfaches Beispiel wird wahrscheinlich Sie in der richtigen Gemütszustand gesetzt ist, geht so hier:
/users/uid
/users/uid/email
/users/uid/messages
/users/uid/widgets
Jetzt, da wir in einer hierarchischen Struktur sind, wenn ich E-Mail-Adressen der Benutzer iterieren möchten, Ich mache etwas in der Art:
// I could also use on('child_added') here to great success
// but this is simpler for an example
firebaseRef.child('users').once('value')
.then(userPathSnapshot => {
userPathSnapshot.forEach(
userSnap => console.log('email', userSnap.val().email)
);
})
.catch(e => console.error(e));
Die Problem mit diesem Ansatz ist, dass ich den Client gezwungen habe, alle messages
und widgets
Benutzer auch zu downloaden. Keine große Sache, wenn keines dieser Dinge in Tausenden zählt. Aber eine große Sache für 10k Benutzer mit jeweils mehr als 5k Nachrichten.
So, jetzt die optimale Strategie für eine hierarchische, Echtzeit-Struktur wird deutlicher:
/user_meta/uid/email
/messages/uid/...
/widgets/uid/...
Ein zusätzliches Werkzeug, das sehr nützlich in diesem Umfeld ist Indizes sind.
/users_with_gmail_accounts/uid/email
Nun, wenn ich will, sagen wir, Nachrichten für Google Mail-Nutzer bekommen, kann ich so etwas tun: einen Index von Benutzern mit bestimmten Attributen Durch das Erstellen, kann ich schnell eine SQL-Abfrage, indem Sie einfach eine Iteration des Index simulieren :
var ref = firebase.database().ref('users_with_gmail_accounts');
ref.once('value').then(idx_snap => {
idx_snap.forEach(idx_entry => {
let msg = idx_entry.name() + ' has a new message!';
firebase.database().ref('messages').child(idx_entry.name())
.on(
'child_added',
ss => console.log(msg, ss.key);
);
});
})
.catch(e => console.error(e));
ich in einem anderen einige Details angeboten SO über Denormalisierung Daten veröffentlichen, so check those out as well. Ich sehe, dass Frank bereits Anants Artikel gepostet hat, also werde ich das hier nicht wiederholen, aber es ist auch eine tolle Lektüre.
Danke für diese Einsicht Kato! –
Muss ich diese Indizes manuell verwalten? – fiatjaf
Vorerst. Die Ansichten in der Version 2 von Firebase enthalten einige großartige Funktionen zur Automatisierung dieses Prozesses. – Kato