Structure a NoSQL database for a chat application (using FireBase)
Asked Answered
B

2

15

Coming from years of using relational databases, i am trying to develop a pretty basic chat/messaging app using FireBase

FireBase uses a NoSQL data structure approach using JSON formatted strings.

I did a lot of research in order to understand how to structure the database with performance in mind. I have tried to "denormalize" the structure and ended up with the following:

{

"chats" : {

    "1" : {
        "10" : {
            "conversationId" : "x123332"
         },
        "17": {
            "conversationId" : "x124442"
        }
    }
},

"conversations" : {

    "x123332" : {

      "message1" : {

        "time" : 12344556,
        "text" : "hello, how are you?",
        "userId" : 10
      },
      "message2" : {

        "time" : 12344560,
        "text" : "Good",
        "userId" : 1
      }
    }
  }
}

The numbers 1, 10, 17 are sample user id's.

My question is, can this be structured in a better way? The goal is to scale up as the app users grow and still get the best performance possible.

Binoculars answered 13/3, 2016 at 11:34 Comment(3)
Firebase data structures depend on what you want to do with the data. What is presented is very expandable, query'able and the nodes are observable for changes. Also, Firebase is blisteringly fast and can easily handle thousands of requests. However, without understanding the full scope, or a specific question about the data, it's an open ended question. For example; what's the function of the chat's node? The conversations node contains everything needed to track a conversation with another user. e.g. User logs in, queries all conversations that contain their user id and then observes them.Psychosomatic
Think of it as a basic WhatsApp app, where you have an activity that display all my chats. When i click on a chat i get the "detailed view" which is the conversation messages between the two users.Binoculars
The question itself explains what the app does but the use of the structure is to vague; the functionality described could easily be done with just the conversations node. Denormalizing data is very important but don't do it just for the sake of creating another node when it's not necessary. In this case it may or may not be necessary. The question needs to be a lot more specific so I would suggest crafting up some code for testing and when you run into an issue, then post your specific question.Psychosomatic
F
11

Using the document-oriented database structure such Firestore, you can store the conversations as below;

{
   "chat_rooms":[
      {
         "cid":100,
         "members":[1, 2],
         "messages":[
           {"from":1, "to":2, "text":"Hey Dude! Bring it"},
           {"from":2, "to":1, "text":"Sure man"}
          ]
      },
      {
         "cid":101,
         "members":[3, 4],
         "messages":[
           {"from":3, "to":4, "text":"I can do that work"},
           {"from":4, "to":3, "text":"Then we can proceed"}
          ]
      }
   ]
}

Few examples of NoSQL queries you could run through this structure.

Get all the conversations of a logged-in user with the user id of 1.

db.chat_rooms.find({ members: 1 })

Get all the documents, messages sent by the user id of 1.

db.chat_rooms.find({ messages: { from: 1 } })

The above database structure is also capable of implementing in RDMS database as table relationships using MySQL or MSSQL. This is also can be implemented for group chat room applications.

This structure is optimized to reduce your database document reading usage which can save your money from paying more for infrastructure.

According to our above example still, you will get 2 document reads since we have 4 messages but if you store all the messages individually and run the query by filtering sender id, you will get 4 database queries which are the kind of massive amount when you have heavy conversation histories in your database.

Fenestra answered 21/5, 2020 at 6:24 Comment(0)
N
3

One case for storing messages could look something like this:

"userMessages": 
    { "simplelogin:1": 
        { "simplelogin:2": 
            { "messageId1": 
                { "uid": "simplelogin:1", 
                  "body": "Hello!", 
                  "timestamp": Firebase.ServerValue.TIMESTAMP },
               "messageId2": { 
                  "uid": "simplelogin:2", 
                  "body": "Hey!", 
                  "timestamp": Firebase.ServerValue.TIMESTAMP } 
                 } 
             } 
         } 

Here is a fireslack example this structure came from. This tutorial builds an app like slack using firebase: https://thinkster.io/angularfire-slack-tutorial

If you want something more specific, more information would be helpful.

Neil answered 13/3, 2016 at 13:59 Comment(3)
but what is simplelogin2 logs in, how will you find the chat messages for this user?Defaulter
You would probably store the same information under simplelogin2. Yes, it duplicates information in the database, but that's often the price you pay for quick query times in NoSQL.Neil
do you have more examples maybe? it's so weird and counter intuitive to have everthing twice or more in the database. on the firebase website (firebase.google.com/docs/database/web/structure-data) there is a different structure for a chat app but I don't get how you can read this data, there are keys one, two, three.. but if I'm logged in as 'ghopper', how can I find the correct key for the current chatDefaulter

© 2022 - 2024 — McMap. All rights reserved.