I'm making a blog app using firebase.
I want to know the best practice of data structure.
As far as I know, there are 2 case. (I'm using react native)
case 1:
posts
-postID
-title,content,author(userID),createdDate,favoriteCount
favorites
-userID
-favoriteList
-postID(onlyID)
-postID(onlyID)
In this case, for example, when we need to get favorite posts.
firebase.firestore().collection(`favorites/${userID}/favoriteList`)
.get()
.then((snapshot) => {
snapshot.forEach((favorite) => {
firebase.firestore().collection(`favorites/`).doc(`${favorite.id}`)
.get()
.then((post) => {
myPostList.push(post.data())
});
});
in this case, we can't order the favorite posts by createdDate
. So, need to sort client side. Even if so, we don't use limit() function.
case 2:
posts
-postID
-title,content,author(userID),createdDate,favoriteCount
favorites
-userID
-favoriteList
-postID
-title,content,author(userID),createdDate,favoriteCount
-postID
-title,content,author(userID),createdDate,favoriteCount
firebase.firestore().collection(`favorites/${userID}/favoriteList`).orderBy('createdDate','desc').limit(30)
.get()
.then((snapshot) => {
snapshot.forEach((post) => {
myPostList.push(post.data())
});
});
in this case, When the favorite post is modified by the author, we have to update all of the favorite posts. (e.g. If 100 users save the post as a favorite, we have to update to 100 data.)
(And I'm not sure we can increment favoritecount
by a transaction, exactly same.)
I think if we use firebase.batch()
, we can manage it. But I think it seems Inefficient.
It seems that both ways are not perfect. Do you know the best practice of this case?
All Firebase Realtime Database data is stored as JSON objects. You can think of the database as a cloud-hosted JSON tree. Unlike a SQL database, there are no tables or records. When you add data to the JSON tree, it becomes a node in the existing JSON structure with an associated key.
Cloud Firestore is a NoSQL, document-oriented database. Unlike a SQL database, there are no tables or rows. Instead, you store data in documents, which are organized into collections. Each document contains a set of key-value pairs.
Firestore is Very Scaleable Without getting too technical, Firestore bakes in a lot of best practices when it comes to running a scalable database so developers don't have to. Since Firestore is backed by Google Cloud Platform, you can rest assured that your database can scale to meet your needs.
What about using arrays or Collection Groups?
posts
-postID
-title,content,author(userID),createdDate,favoriteCount
-[favoriters(userID)]
Now you can query for a user's favorites by querying posts that "array-contains" the user's ID. You can also modify individual posts without iterating through a bunch data copies.
There's a limit to this approach though. Maximum size for a document is 1 MiB; assuming that a user ID is 4 bytes, a document can contain no more than 250K favoriters. Clients would also have to do some O(N) processing to add / remove favoriters.
posts
-postID
-title,content,author(userID),createdDate,favoriteCount
-favoriters {collection}
-userID
A collection group consists of all collections with the same ID. By default, queries retrieve results from a single collection in your database. Use a collection group query to retrieve documents from a collection group instead of from a single collection.
So we can fetch a user's favorite posts via
db.collectionGroup("favoriters").whereEqualTo("userID", <userID>).get();
To favorite a post, we just do
const postsRef = db.collection("posts");
postsRef.document(<postID>).collection("favoriters").add({ "userID", <userID> });
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With