2016-05-29 1 views
11

Im folgenden Firebase-Handbuch zu structuring data für eine Chat-App. Sie schlagen die Struktur vor, wie unten gesehen.Strukturieren von Daten für die Chat-App in Firebase

{ 
    // Chats contains only meta info about each conversation 
    // stored under the chats's unique ID 
    "chats": { 
    "one": { 
     "title": "Historical Tech Pioneers", 
     "lastMessage": "ghopper: Relay malfunction found. Cause: moth.", 
     "timestamp": 1459361875666 
    }, 
    "two": { ... }, 
    "three": { ... } 
    }, 

    // Conversation members are easily accessible 
    // and stored by chat conversation ID 
    "members": { 
    // we'll talk about indices like this below 
    "one": { 
     "ghopper": true, 
     "alovelace": true, 
     "eclarke": true 
    }, 
    "two": { ... }, 
    "three": { ... } 
    }, 

    // Messages are separate from data we may want to iterate quickly 
    // but still easily paginated and queried, and organized by chat 
    // converation ID 
    "messages": { 
    "one": { 
     "m1": { 
     "name": "eclarke", 
     "message": "The relay seems to be malfunctioning.", 
     "timestamp": 1459361875337 
     }, 
     "m2": { ... }, 
     "m3": { ... } 
    }, 
    "two": { ... }, 
    "three": { ... } 
    } 
} 

Wie kann ich meine Benutzerdaten strukturieren, so dass ich einfach eine Liste aller von den Chats anzeigen kann sie Teil und für jeden von ihnen zeigen die letzte Nachricht und Zeitstempel sind. Wenn ich die folgende Struktur zu tun:

"users": { 
    "ghopper": { 
     "name": "Gary Hopper", 
     "chats": { 
      "one: true", 
      "two": true 
     } 
    }, 
    "alovelace" { ... } 
    }, 

Ich kann leicht eine Liste aller Chat-Gruppe für einen bestimmten Benutzer, zum Beispiel ghopper erhalten, indem (in swift) tun:

ref.child("users").child("ghopper").child("chats").observeSingleEventOfType(.Value, withBlock: { (snapshot) in 
    //do something with data 
} 

Jedoch habe ich gewonnen Habe in diesem Snapshot nicht die letzte Nachricht und den Zeitstempel. Was muss ich tun, um auf diese Daten zuzugreifen?

  • Duplizieren Sie alle diese Daten für jeden Benutzer? dh Hinzufügen von Benutzern/ghopper/chats/one/{"lastMessage": "ghopper: Relaisfehler gefunden. Ursache: Moth.", "timestamp": 1459361875666}
  • Stellen Sie für jeden Chat eine Abfrage nach "chats/specificGroupId" Der Benutzer ist Teil von (Hinzufügen mehrerer Listener)?
  • Ein anderer Weg?

Antwort

2

In dem Block, wo Sie eine Liste aller Chats ein Benutzer ist, können Sie tun:

var dictionary: [String: Long] 
var lastMessage: String 
for chat in listOfChatsUserIsIn 
    ref.child("chats").child("\(chat)").child("lastMessage").observeSingleEventOfType(.Value, withBlock: { (snapshot) in 
     lastMessage = snapshot 
     ref.child("chats").child("\(chat)").child("timestamp").observeSingleEventOfType(.Value, withBlock: { (snapshot) in 
      //add timestamp and last message to dictionary 
     } 
    } 

Ich weiß nicht, wie richtig meine Syntax ist. Ich lerne immer noch Firebase. Aber ich denke, das ist im Grunde Ihr zweiter Vorschlag. Ich weiß nicht, wie sonst Sie die Daten bekommen würden. Das wäre O (2n), was aber nicht schlecht ist.

[[Update 1]]

ich mit meinem Code faul war. Ich habe lastMessage = snapshot abgelegt, um es zu speichern, damit Sie es im nächsten Block zum Wörterbuch hinzufügen können.

Da Firebase asynchron ist. Ich denke, das würde immer noch funktionieren, solange Sie entweder den Zeitstempel oder die Nachricht als Schlüssel und den anderen als Wert im Wörterbuch verwenden. Es kann in der falschen Reihenfolge angezeigt werden, aber Sie können es später immer nach Zeitstempel sortieren. Obwohl, ja, das ist wahrscheinlich keine Best Practice.

Jay, ich mag deine Lösung. Müsstest du nicht auch uid_2: false auflisten?

Leider scheinen beide Datenbankstrukturen um n^2 als Benutzer zu wachsen -> inf und als Chats -> inf.

+0

Was ist die Funktion von lastMesssage = Snapshot, da Sie diese Variable nicht verwenden? Es ist auch eine gute Übung, den Namen "self.variable" in einem Block (closure) zu verwenden. Außerdem ist das ref.child innerhalb des ersten ref.child ein Duplikat, so dass es die gleichen Daten lesen wird. Das größte Problem ist, dass Firebase asynchron ist und dass die Tight for-Schleife * schneller * läuft als die Daten innerhalb des Beobachtungsblocks zurückgegeben werden können. Daher denke ich, dass wir Probleme mit der Datenintegrität haben - wahrscheinlich sollte Firebase dies tun "stopfen" asynchron. – Jay

+0

Um die Frage in Ihrer Antwort zu beantworten .... Nein, uid_2: false wird nicht benötigt, als ob es nicht existiert, es könnte standardmäßig falsch sein (hängt von seinem Code ab). Und nein, die Datenbank wächst nicht exponentiell. Wenn Sie 10 Benutzer und einen Chat haben, sind alle 10 Benutzer in diesem Chat, so dass nur der Benutzerknoten im Chat (in meiner Antwort) wächst. Wenn Sie 1000 Benutzer und 100 Chats haben, wird jeder Chat mit zwei Benutzern durchgeführt , das sind immer noch nur 100 Chats, die jeweils einen Benutzerknoten mit zwei Benutzern haben. Selbst bei 1000 Benutzern und 1000 Chats ist das keine wesentliche Datenmenge. – Jay

17

Wie strukturiere ich meine Benutzerdaten so, dass ich einfach eine Liste von alle der Chats anzeigen kann sie Teil und für jeden von ihnen zeigen die letzte Meldung und Zeitstempel sind.

Ändern der Chats Struktur ein bisschen durch das Hinzufügen von Benutzern, die

"chats": { 
    "one": { 
     "title": "Historical Tech Pioneers", 
     "lastMessage": "ghopper: Relay malfunction found. Cause: moth.", 
     "timestamp": 1459361875666 
     users 
     uid_1: true 
     uid_3: true 
    }, 
    "two": { ... }, 

Dann im Chat Knoten sind, können Sie tief Abfrage für alle Chats ein bestimmter Benutzer gehört - das wird wieder die Chats uid_3 ist involvierte in

chatsRef.queryOrderedByChild("users/uid_3").queryEqualToValue(true) 
    .observeSingleEventOfType(.Value, withBlock: { snapshot in 

    //.Value can return multiple nodes within the snapshot so iterate over them 
    for child in snapshot.children { 
      let lastmsg = child.value["lastMessage"] as! String 
      let timestamp = child.value["timestamp"] as! String 
      print(lastmsg) 
      print(timestamp) 
    }  
}) 

beachten, dass jeder Benutzer Feuerbasis erhielt eine diskrete Benutzer-ID hat, wenn der Benutzer über auth.uid erstellt wird. Dies sollte (allgemein) als Schlüssel für jeden Benutzer verwendet werden.

+1

Hallo Jay, danke für deine Antwort. Ich habe deine Lösung versucht und es scheint der Trick zu sein. Aber wird diese Operation nicht viel zu teuer, sobald ich viele Benutzer habe, wenn ich bedenke, dass ich alle "Chats" durchsehen muss, um alle Chats zu finden, zu denen der Benutzer gehört? – Nilsymbol

+1

@Nilsymbol Froh, dass es funktioniert hat! Es scheint nicht so zu sein, als würdest du Megabytes an Daten runterziehen, nur ein paar hundert Knoten mit einigen Kindern. Firebase ist blitzartig schnell, so eine Abfrage wie diese auf Tausenden von Knoten ist super schnell; Es wird Firebase nicht einmal schwer atmen lassen. Wir haben es getestet! – Jay

+0

@Jay Ich verstehe die Struktur zum größten Teil, einfach nicht verstehen, wie Benutzer in den "Chats" Kinder vertreten sind. Ist es ein Array der Benutzer-UID? Könntest du die Verbindung des Boolean mit der UID bitte etwas mehr erklären? Vielen Dank! -Colbey – justColbs