Best Way to Structure My Firebase Database

What are some good ways to structure data in firebase?

I'll go ahead and leave an answer for how I would approach this. My answer will be geared more towards Firestore even though the question is marked as Realtime Database. There are multiple ways to structure the data. This is the general structure I would use given your example:

users
- name
- timestamp

posts
- imageURL
- description
- timestamp
- likeCount
- commentCount

posts/comments //subcollection
- userID
- comment
- timestamp

posts/likes //subcollection
- userID
- timestamp

savedposts
- postID
- userID

followers
- userID
- followedID

Some additional notes:

Image Upload

The best option here is to upload the images to cloud storage and utilize a cloud function to generate a public URL and save it to the post document.

Comment / User Search

As stated in my comment, Firebase does not have a great solution for text based searches. The solution I utilized in my project was to utilize a cloud function to keep an Algolia index in sync with my users collection. I then offload the user search to them through a callable cloud function - though you could utilize the Algolia client SDK directly in your app if you wanted. In your scenario, you would also have to keep all of your comments in sync as well. Algolia isn't a cheap service, so I would look into the pros / cons of using the other options listed in the docs.

Document IDs

I generally let Firestore auto ID the documents, but here I would make some exceptions. For the savedposts and followers collections I would utilize a (manual) compound ID of {userID}{postID} and {userID}{followedID} respectively. It allows you to perform simple actions of unliking and unfollowing without querying for the document first. Ex) firestore().collection('postsaves').doc(`${userID}${postID}`).delete()

Final Thoughts

You mention maybe moving to AWS. I have worked much more in Firebase than in AWS, but I have done both. In my opinion, Firebase is unmatched in both usability and documentation. There are some compromises in terms of functionality and fine tuning but I recommend sticking with Firebase if the lack of text searching is the only hurdle.

Recommendations for Firebase database structure

If you can shard/partition the data so that you don't need to query a potentially very long list of that, that is always preferable with the realtime database.

So in your case, if you know that you want to show the user a list of their own posts as a starting point, it is a good idea to model that list in your database. You'd typically call this the user's feed or wall, depending on what your social network of choice is.

If you then later want to also show the posts of users they follow, you might want to store those posts in the user's wall. This type of data duplication may seem unnatural at first, but is quite common in NoSQL databases. In fact, this is the exact model that Firebase uses in its class FireFeed example.

To learn more about NoSQL data modeling, see:

  • NoSQL data modeling.
  • Firebase for SQL developers.
  • Getting to know Cloud Firestore, which is about Firebase's newer Firestore database, but has great tips that apply to the Realtime Database too.

Best way to structure my firebase database

Working with NoSql Data , your need to take care of few things:-

  • Avoid Nesting The Data Too Deep
  • Flatten your dataStructure as possible
  • Prefer Dictionaries
  • Security Rules [Firebase]

Try this structure:-

users:{
userID1: {..//Users info..
posts:{
postID1: true,
postID2: true,
postID3: true,
}
},
userID2: {..//Users info..},
userID3: {..//Users info..},
userID4: {..//Users info..},
},
posts: {
userID1 :{
postID1: {..//POST CONTENT },
postID2: {..//POST CONTENT },
postID3: {..//POST CONTENT },
}

}

Correct way to structure firebase database by dates

This way:

objects
- objectA
- 2020:01:22:01
- property1 : "Value at 1 o'clock on the 22nd of Jan, 2020"
- property2 : "Value at 1 o'clock on the 22nd of Jan, 2020"
- 2020:01:22:02
- property1 : "Value at 2 o'clock on the 22nd of Jan, 2020"
- property2 : "Value at 2 o'clock on the 22nd of Jan, 2020"
...
- objectB
...

Is better than option 1, always favor using a flat data structure instead of a nested one. If you have difficulties retrieving the month or the day, you can add them both as a property:

objectA
2020:01:22:01
property1 : data
month : 01
day : 22

But you can also use getKey() and then use split to retrieve the month and day.

https://firebase.googleblog.com/2013/04/denormalizing-your-data-is-normal.html?m=1

What's the best way of structuring data on firebase?

UPDATE: There is now a doc on structuring data. Also, see this excellent post on NoSQL data structures.

The main issue with hierarchical data, as opposed to RDBMS, is that it's tempting to nest data because we can. Generally, you want to normalize data to some extent (just as you would do with SQL) despite the lack of join statements and queries.

You also want to denormalize in places where read efficiency is a concern. This is a technique used by all the large scale apps (e.g. Twitter and Facebook) and although it goes against our DRY principles, it's generally a necessary feature of scalable apps.

The gist here is that you want to work hard on writes to make reads easy. Keep logical components that are read separately separate (e.g. for chat rooms, don't put the messages, meta info about the rooms, and lists of members all in the same place, if you want to be able to iterate the groups later).

The primary difference between Firebase's real-time data and a SQL environment is querying data. There's no simple way to say "SELECT USERS WHERE X = Y", because of the real-time nature of the data (it's constantly changing, sharding, reconciling, etc, which requires a simpler internal model to keep the synchronized clients in check)

A simple example will probably set you in the right state of mind, so here goes:

/users/uid
/users/uid/email
/users/uid/messages
/users/uid/widgets

Now, since we're in a hierarchical structure, if I want to iterate users' email addresses, I do something like this:

// I could also use on('child_added') here to great success
// but this is simpler for an example
firebaseRef.child('users').once('value')
.then(userPathSnapshot => {
userPathSnapshot.forEach(
userSnap => console.log('email', userSnap.val().email)
);
})
.catch(e => console.error(e));

The problem with this approach is that I have just forced the client to download all of the users' messages and widgets too. No biggie if none of those things number in thousands. But a big deal for 10k users with upwards of 5k messages each.

So now the optimal strategy for a hierarchical, real-time structure becomes more obvious:

/user_meta/uid/email
/messages/uid/...
/widgets/uid/...

An additional tool which is extremely useful in this environment are indices. By creating an index of users with certain attributes, I can quickly simulate a SQL query by simply iterating the index:

/users_with_gmail_accounts/uid/email

Now if I want to, say, get messages for gmail users, I can do something like this:

var ref = firebase.database().ref('users_with_gmail_accounts');
ref.once('value').then(idx_snap => {
idx_snap.forEach(idx_entry => {
let msg = idx_entry.name() + ' has a new message!';
firebase.database().ref('messages').child(idx_entry.name())
.on(
'child_added',
ss => console.log(msg, ss.key)
);
});
})
.catch(e => console.error(e));

I offered some details in another SO post about denormalizing data, so check those out as well. I see that Frank already posted Anant's article, so I won't reiterate that here, but it's also a great read.

How should I structure my data in Firebase

Better to stick with 1 source of truth. Between the two I would choose firestore.

There is a pretty good comparison between the two and their tradeoffs here. Do you care only about mobile or do you want your app to work on web and mobile? I'd go with firestore if that is the case.

https://firebase.google.com/docs/database/rtdb-vs-firestore

Also you mention you have Usernames, Users, and Posts in your database. You should be storing usernames in your "Users" collection so you would really only have two different collections for these "Users" and "Posts". Also between the two, you are likely going to have more posts than there are users.

Whats the best way to structure Firestore database?

It's good to hear that the following structure:

  • What is the correct way to structure this kind of data in Firestore?

Answers your question, but regarding:

Do I get fewer reads & writes if you structure your database with more sub-collections/documents like the image above?

No, it doesn't really matter if you query a collection or a sub-collection, you'll always have to pay a number of reads that is equal to the number of documents that are returned.

Also which of the two options can reach usage limits faster?

The structure doesn't matter. What it really matters is the number of requests you perform.



Related Topics



Leave a reply



Submit