Data Modeling Best Practices in Firebase/AngularFire

All we need is an easy explanation of the problem, so here it is.

I’m developing an application in Firebase for the first time and was curious how I should model the data between two objects, a user and a post. I come from more of a relational db background and was curious not only how this would be done in nonrelational DBs but specifically how to set up a relationship between two objects in Firebase.

For example, my application has many Users, and each user creates many Posts.

User {
    firstName: String,
    lastname: String,
    userName: String
}

Post {
    title: String,
    content: String,
    date: Date,
    writtenBy: [User object?]
}

How should I structure these two objects in Firebase so that a Post belongs to a User, but all Posts can be queried for regardless of User, and both User and Post objects can be edited without disrupting the other object’s data and/or relationship?

And how should I create new “relational” objects via firebase:

sync.$set({userA: {
   firstname: "Billy",
   lastName: "Bob",
   userName: "BillyBob",
   Posts: {
       // .....
   }
}
});

Thanks!

How to solve :

I know you bored from this bug, So we are here to help you! Take a deep breath and look at the explanation of your problem. We have many solutions to this problem, But we recommend you to use the first method because it is tested & true method that will 100% work for you.

Method 1

Firebase is built with performance in mind. This is the reason you have to design data structures differently, normalization is your enemy in most cases. Every object in Firebase can be accessed by URL, and you should always keep this in mind.
There are still many ways of designing the data structures, it depends on what queries do you want to execute. If one of the queries is to be able to display all messages (I believe a number of latest messages would be the most common use case), but at the same time you want to be able to show messages per user than one of the possible data structures could look like this:

User {
    userId(assigned by Firebase automatically) {
        firstName: String,
        lastname: String,
        userName: String
    }
}

Post {
    User {
        userId(matching userId in the User object) {
            postId(assigned by Firebase for every new post automatically) {
                title: String,
                content: String,
                date: Date,
                writtenBy: String, userName or userId (this is not really needed, but may keep it for easier data access)
            }
        }
    }
}

Then you can change any user data without triggering data change events in Posts, like in your example, (which would be extremely heavy if you have large number of messages).
You can get all messages independently of user:

var postListRef = new Firebase(URL);
var lastPostQuery = postListRef.child("Post").limit(500);

You can also use startAt() and endAt() quesries https://www.firebase.com/docs/web/api/query/limit.html
As a drawback – you have to unpack every message in the for loop if you need to show only messages, but I would expect you would show user info as well, so it should be ok.

If you want to listen for just one user messages, it’s very simple and fast:

var postListRef = new Firebase(URL);
var lastPostQuery = postListRef.child("Post/User").child(userId);

And Angular/AngularFire has great support for this kind of data structures.

Method 2

I am also new to Firebase, I would recommend the following structure.

Users: {
  userID: {
    firstName: String,
    lastname: String,
    userName: String,
    posts: {
      postID1:true,
      postID2:true
   }

Posts: {
  postID1:{
    title: String,
    content: String,
    date: Date,
    writtenBy: userID
  }
}

It allows you to get the latest posts without having to through any users. Plus you can get all the post made by any user.

Note: Use and implement method 1 because this method fully tested our system.
Thank you 🙂

All methods was sourced from stackoverflow.com or stackexchange.com, is licensed under cc by-sa 2.5, cc by-sa 3.0 and cc by-sa 4.0

Leave a Reply