I want to show feeds for my users.
Every post has a \"like\" button (like in twitter, Instagram...)
I want to show a different icon if the post is already liked o
You could create an array within each post containing the userID's of the users who liked the post.
// data model
posts/{postID}
-- content (string)
-- likes: [
user123,
user567,
user895,
]
Then query the posts like so.
db.collection('posts')
.orderBy('createdAt', 'desc')
.limit(50)
Then inside the snapshot.
db.collection('posts')
.orderBy('createdAt', 'desc')
.limit(50).get()
.then(snapshot => {
if (snapshot.empty) {
console.log('No matching documents.');
return;
}
snapshot.forEach(doc => {
console.log(doc.id, '=>', doc.data());
var liked = false;
var likes = doc.data().likes;
if (likes.includes(user_uid){
liked = true
}
return createPost(doc.data(), liked);
});
})
.catch(err => {
console.log('Error getting documents', err);
});
Then below create a function called createPost()
taking parameters data
and likedStatus
.
Add {likedStatus ? "You liked this" : "Like post"}
into your createPost
function.
createPost = (data, likedStatus) => {
return (
<div class="content">
<div class="liked">
{likedStatus ? "You liked this" : "Like post"}
</div>
</div>
)
}
To solve the problem of like/unlike for your posts, as also @Hudson Hayes mentioned in his answer, I also recommend you try the following schema:
Firestore-root
|
--- posts (collection)
|
--- postId (document)
|
--- //Post details
|
--- userLikes: ["userIdOne", "userIdTwo", "userIdThree"]
As you can see, under each Post
object there is an array that contains user ids. Now, everytime a user likes a post, simply add his id to the userLikes
array. When the user revokes the like, simply remove his id from the array. In this case you'll be charged only with one write operation for each like/unlike.
Now to display a list of all posts and highlight which is liked and which not, simply create a list that contains posts objects. Because you know the id of the authenticated user, simply check the existence of its id in each post userLikes
array. If its id exist in the array show a red heart otherwise show a grey one.
There is no need for additional queries. So IMHO, none of your solutions might apply to this use-case.
Edit:
The size of the document is indeed 1MiB but when we are talking about storing text (user ids), you can store pretty much.
If yes, this wouldn't be a solution for a scaling application.
Yes, it is a solution for scaling. 1Mib can hold 1,000,000 chars, divided to 20, the number of chars an id has, it means 50,000. If you think that your app will be so popular, so a single post will exceed the max number of 50,000 of likes, yes, it's not an option. But there is an workaround. You can create then a subcollection that will documents of likes. Each document will hold 50,000 ids. So for 150,000 likes, you'll have only 3 documents. To check that out, for every post you'll need to create an extra query to get the number of likes (in the above example three) and see if user id is in it.
Storing the likes as individual objects is not an option since for 150,000 likes you'll be charged with 150,000 read operation which is too expensive.
Furthermore it would be an additional query as well, because I couln't get the post data if the user isn't in the likers array.
You can get any data you want but remember, you don't query the users
collection, you query the posts
collection. This collection holds the posts of all users. If you need to see the posts of a single user, add a property inside the document named, createdBy
and add the id of the user who created it. Then a query like this is required:
db.collection("posts").whereEqualTo("createdBy", uid);
To overcome this I would have to load the complete array and filter it on the client side.
There is no need for that. I explained above why.