ZassX
ZassX

Reputation: 1379

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?

Upvotes: 3

Views: 1114

Answers (1)

ArunV
ArunV

Reputation: 111

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)

Upvotes: 5

Related Questions