2013-05-07 21 views
91

Ich bin neu bei Firebase und ich möchte wissen, wie man Daten am besten strukturiert.Was ist der beste Weg, Daten auf Firebase zu strukturieren?

Ich habe ein einfaches Beispiel:

Es gibt Bewerber und Anwendungen auf meinem Projekt. 1 Bewerber kann mehrere Bewerbungen haben. Wie kann ich diese 2 Objekte auf Firebase beziehen? Funktioniert es wie eine relationale Datenbank? Oder muss der Ansatz hinsichtlich des Datenentwurfs völlig anders sein?

Antwort

119

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.

+0

Danke für diese Einsicht Kato! –

+4

Muss ich diese Indizes manuell verwalten? – fiatjaf

+2

Vorerst. Die Ansichten in der Version 2 von Firebase enthalten einige großartige Funktionen zur Automatisierung dieses Prozesses. – Kato

44

Firebase sehr viel nicht wie eine relationale Datenbank. Wenn Sie es mit irgendetwas vergleichen möchten, würde ich es mit einer hierarchischen Datenbank vergleichen.

Anant schrieb vor kurzem einen großen Beitrag über auf dem Blog über Firebase Ihre Daten Denormalisierung: https://www.firebase.com/blog/2013-04-12-denormalizing-is-normal.html

ich in der Tat wie ein Kind jeden Antragsteller die „ID“ jede Anwendung halten würde vorschlagen.

+0

Yuppers! Guter Eintrag! Danke, dass du mich daran erinnert hast. – Kato

+0

Danke Frank! Das ist sehr hilfreich. Genau das, was ich gesucht habe! –

3

Ihr Szenario sieht in der relationalen Welt wie eins zu viele aus, wie in Ihrem Beispiel ein Bewerber viele Anwendungen haben. Wenn wir zu Firebase nosql kommen, sieht es wie folgt aus. Es sollte ohne Leistungsprobleme skalieren. Deshalb brauchen wir die Denormalisierung wie unten erwähnt.

applicants:{ 
applicant1:{ 
    . 
    . 
    applications:{ 
     application1:true, 
     application3:true 
    } 
}, 
applicant2:{ 
    . 
    . 
    applications:{ 
     application2:true, 
     application4:true 
    } 
}} 

applications:{ 
application1:{ 
    . 
    . 
}, 
application2:{ 
    . 
    . 
}, 
application3:{ 
    . 
    . 
}, 
application4:{ 
    . 
    . 
}} 
+0

Gut, aber ich habe eine Folge, wie erstellen wir diese Struktur von Swift oder von überall mit dem Firebase SDK? Wie können wir außerdem überprüfen, ob die neuen Daten, die dem Anwendungsknoten hinzugefügt wurden, tatsächlich in der Anwendungsliste vorhanden sind, die Firebase-Validierungsregeln verwendet? –

+0

@prateep, Gutes Beispiel. Aber hier Problem ist, wenn ich Pfad Anwendungen/application1 löschen, wo application1 Kind für einige Bewerber ist. Wenn ich versuche, auf Pfadbewerber/application1 zuzugreifen, die nicht dort sind. Also müssen Sie die Indizes an beiden Stellen aktualisieren, wie in application1: {bewerber: {bewerber1: true} ...}. Jetzt, wenn ich bewerber1 lösche, muss ich prüfen, ob es sich um untergeordnete Bewerber handelt, und den Kindknoten des Antragstellers für die Bewerbung aktualisieren. :) –

Verwandte Themen