Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Firebase data structuring (best practice)

I am just starting with NoSQL structures so I have a question about data structuring.

We are developing an app that will have groups. You can create a group (Work, Home, Close Friends, Custom) and select users which will be included in it. Each user will have his own groups.

There will be also option to create chats with that people - user can create multiple chats with different people.

I created a json structure so if you could just check if it is denormalised or if I can improve it somehow.

{
  "groups" : {
    "gid1" : {
      "name" : "This is first group",
      "members" : {
        "uid1" : true,
        "uid2" : true
      }
    },
    "gid2" : {
      "name" : "This is second group",
      "members" : {
        "uid2" : true,
        "uid3" : true
      }
    }
  }, 

  "chats" : {
    "cid1" : {
      "members" : {
        "udi1" : true,
        "uid2" : true
      },
      "messages" : {
        "m1" : true,
        "m2" : true,
        "m3" : true
      }
    }
  },

  "messages" : {
    "m1" : {
      "message" : "Test Message",
      "author" : "AuthorName"
    },
    "m2" : {
      "message" : "Test Message 2",
      "author" : "AuthorName2"
    },
    "m3" : {
      "message" : "Test Message 3",
      "author" : "AuthorName3"
    }
  },

  "users" : {
    "uid1" : {
      "email" : "[email protected]",
      "name" : "FirstUser",
      "groups" : {
          "gid1" : true
        },
        "friends" : {
          "uid2" : true
        },
        "chats" : {
          "cid1" : true
        } 
    },
    "uid2" : {
      "email" : "[email protected]",
      "name" : "SecondUser",
      "groups" : {
          "gid1" : true,
          "gid2" : true
        },
        "friends" : {
          "uid1" : true
        },
        "chats" : {
          "cid1" : true
        } 
    }
  }
}

Also code question (iOS, Swift): So with structure like that, I can call: /users/uid1/groups. How can I get all the groups I have created? Currently my code looks like this:

func getGroups(callback:([Group]) -> ()) {
        NSLog("Get groups called")
        var groupsArray:[Group] = [Group]()
        var appendCounter = 0

        self.ref?.child("users").child(currentUser!.uid).child("groups").observeSingleEventOfType(.Value, withBlock: { (snapshot: FIRDataSnapshot) in
            let tempGroups = snapshot.children
            let snapshotCount = snapshot.childrenCount

            while let group = tempGroups.nextObject() as? FIRDataSnapshot {
                self.ref?.child("groups").child(group.key).observeSingleEventOfType(.Value, withBlock: { (snapshot: FIRDataSnapshot) in
                    let groupDict = snapshot.value as! [String : AnyObject]
                    let tempGroup = Group()
                    tempGroup.key = group.key
                    tempGroup.name = groupDict["name"] as? String

                    groupsArray.append(tempGroup)
                    appendCounter += 1

                    if appendCounter == Int(snapshotCount) {
                        callback(groupsArray)
                    }
                })
            }
        }, withCancelBlock: { (error:NSError?) in
            if let error = error {
                print(error.description)
            } else {

            }
        })
    }

Is this right approach?

like image 866
ZassX Avatar asked May 27 '26 16:05

ZassX


1 Answers

While it entirely depends on how you'll be fetching and displaying the data, the main issue I see is that to get all the messages in a particular chat with your current structure, you would query chats/cid1/messages and then query the messages data for each m1, m2, etc.

A better approach would be to structure the messages data with the chat id as the key and you don't need to save the messages object in the chats object:

"messages": {
    "cid1": {
        "m1": {
            "message": "Test Message",
            "author": "AuthorName",
            "timestamp": 1459361875337
        },
        "m2": { ... },
        "m3": { ... }
    }
}

When you need to fetch all the messages in a chat you can just query messages/cid1. You can do the same for members if you like, and leave the chats object to only hold meta data about the conversation e.g. name of the chatroom, last message, etc.

Reference: https://firebase.google.com/docs/database/ios/structure-data#flatten_data_structures

On the iOS side what you have works, you can simplify it by getting rid of the counter since the while loop will exit on its own after the last object.

while let group = tempGroups.nextObject() as? FIRDataSnapshot {
    // create you group object
    // append to groupsArray
}
callback(groupArray)
like image 165
ArunV Avatar answered May 30 '26 02:05

ArunV



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!