d123546
d123546

Reputation: 247

Angular2 Firebase, Chat Application

I'm currently trying to implement private chat messaging in my Angualar2 application. Currently I'm using AngularFire2 to work with a firebase. My Messages got a structure like:

Messages
  message_id_0
    from: user_id_0
    to:   user_id_1
    type: "private"
    message: "a private message"

But currently I can only select messages from one user_id.

this.af.database.list('messages', {
          query: {

              orderBy: "from",
              equalTo: auth.uid,
...

So my questions is, how to select all messages with "from" field name for user_1 and user_2 ? Since Firebase doesn't support WHERE clause, its a challenge for me(

Upvotes: 0

Views: 690

Answers (1)

ProfDFrancis
ProfDFrancis

Reputation: 9411

Create another field consisting of the "from" userId combined with the "to" userId, and query on that field

If I understand correctly, you want to show one user, e.g. Jim, all the messages between Jim and a particular other user, e.g. Sharon. The easiest way is to create a new field in the data.

Messages
  message_id_0
    from: user_id_0
    to:   user_id_1
    fromTo: user_id_0 * user_id_0        // <------- added field
    type: "private"
    message: "a private message"

// e.g. An example dataset might be:

Messages
  message_id: 5903784520934857403
    from: Jim
    to: Sharon
    fromTo: Jim*Sharon
    type: "private"
    message: "whatever"

Then you can use your angularfire snippet, but orderBy the fromTo field.

Separator

It is worth using a separator (here I have used an asterisk) between the userIds, because if you don't, there could be an unintended collision, for example these two different pairs of users would have the same fromTo value:

from: chris
to: topher
fromTo: christopher

from: christ
to: opher
fromTo: christopher

If they have a separator character, such as "*", then the fromTo's become different. Make sure to use a character that cannot occur in a userId.

Other index fields

If you need to pick up messages that go in the reverse direction also (i.e. Sharon to Jim), I can think of two solutions:

  1. Do one query for Sharon*Jim and another for Jim*Sharon
  2. Create yet another field fromToSorted where you sort the two userIds alphabetically before combining them, so that both directions of communication will produce the same value, Jim*Sharon.

This can obviously be extended to include an extra field for every combination you might wish to search or sort on.

Where to do this?

The logical place in the program to create these extra fields is at the place a message is created. In your example question, the fields you chose to index on are ones whose values cannot change after they are created.

Readers wanting to use this approach for fields whose values can change, will probably want to make the code that creates these extra fields into a function that can be called whenever the raw fields are created or may have been edited.

Isn't this against the policy of not storing the same data multiple times?

Yes. That policy, of Normalization, is from an era when data storage was more expensive, and people were willing to wait for a computer to process multiple tables to spit out an answer. Now data storage, for the type of task you describe, is trivially cheap, and people want quick responses. So in Firebase and other NoSQL databases we are happy to Denormalize data where this helps a time-critical task.

One final warning: the second big benefit of Normalization was that if each data item, e.g. the message "from" field, is only stored once, there is no chance that our software might accidentally only update one copy and not the other. Therefore when we denormalize the database, as I described in this answer, we must be absolutely rigorous in making certain that all the extra fields (here the just the fromTo and fromToSorted fields) are updated whenever from or to are updated.

Upvotes: 2

Related Questions