Firestore Rules - Array validation - firebase

I am using firestore for creating a food blog where users can upload posts and like it.
Call it facebook for food.
Below I will give you summary of 2 firestore database collections which are going to be used in my question.
First is Users - where the document name is based on UID and it stores information like, username/emailID
Second is Posts - where the document name is based on UID, however in the structure of the collection
It has a column named as "Likes" which is an array object. This stores 2 values : 1. Name of the person who liked the post and 2. UID of the person who liked the post.
Please find the structure of LIKES column in posts document below :
I am trying to add more validations to the likes part of the document.
However, from postman it is possible to change the name of the person who is liking the post.
The logic of the restrictions has to be on 2 things.
LIKES - UID should be present in my users collection. Also, UID in LIKES column shouldn't be changeable.
LIKES - Name should not be allowed to be changed.
I tried a of way of doing it but it doesnt work :
exists(/databases/$(database)/documents/users/$(request.resource.data.likes[request.resource.data.likes.size() -1].userId))
What it does is checks the last UID of person liking that document. However, in this scenario if there are more than 1 Likes, the name/uid could be altered for the ones which were present earlier.
Not a very efficient way.
Also, Loops dont work in rules so I cant loop it up to get it.
Any help would be really appreciated.
Please let me know if there are any more snippets which would be required.

Related

Firestore Rules to check if user liking post exists in users Cloud Firestore

I'd like to check if the user liking the post is already present in our users cloud Firestore.
There are two different collections here, need to check if one's reference is present in another.
Users collection has user details - UID/Name/Email
Posts collection has details : Post Text / Post Likes / Post Comments
Where Likes is an Map which has userId of person who has liked the image and userName.
From backend its possible to exploit the posts collection and enter malicious value in post documents.
I am trying to achieve this for ON UPDATE condition : To check the user liking post exists in users collection.
------ Tried Below So far but it doesnt work --------------------
match /posts/items/{document}
allow update: if exists(/database/$(database)/documents/users/$(request.resource.data.likes.userId));
What I want is to check if the users liking are already existing or not.
This doesnt work because the likes column is an array and can have multiple objects.
Any help would be great.

How to structure a like query in Firestore?

I'm building a simple application where posts appear on a user's home page and he can like or unlike them.
first when there were no users in the applications, I made a simple boolean field "liked", as shown in the figure, to determine if a post is liked or un-liked. However, when I started working with users, I find it hard to find the perfect structure for the likes field.
In Firestore, I added a field named "likedBy" for each post, which contains a map with a key of each user's id and a boolean to determine if the user liked the post or not.
I don't know if this structure is suitable or not, and if not, is there a better way to reach my goal?
The likedBy field is enough to cover most use cases.
Just store in likedBy an array of all users who liked the post by user ID. When a user likes - add the user ID to the array and remove it upon unlike.
That means you can also remove the likes and liked field as you can get it from reading the likedBy array.
I would recommend going one step further and save more than the User ID. You could also save the User displayName and photoUrl. That way, you don't need to read ($$$$money$$$$) the documents of every Users who liked Posts in order to display their name and/or avatar.

Is there a method to find the values of an array from a collection in a separate collection in Firestore?

I have two collections users and uploads. The user collection shows details about the users that have registered to the app. It contains details about the user such as name, userid and following which is an array. The following array contains list of people that the user is following as shown here.
The uploads collection has the posts that are made by the users. Each document in the uploads collection has details such as the postid, post and name of the user who posted it as shown here.
I want to get only the uploads made by the users whom they are following.
For example, Sally follows three people Sam, Thomas and Ellie. I want Sally to get only the uploads that
are made by either of these three people from the uploads collection. Any help would be appreciated. Thank You
I think this might be what you're looking for. You could fetch the users' following array and then use that array to fetch uploads containing people from the following. As a sidenote I'd recommend the userId instead of the name of the user as these might not be unique.

How can I make sure to fetch only the x most recent posts in DB?

I am trying to fiigure out how exacly I should make sure that I only fetch the most recent x posts from the DB.
My current fetch methods work as follows:
GetPeopleIFollowAnd loop over each UID
For each UID fetch his posts
By doing this however I cant efficiently (quickly) fetch only the most recent x posts. How can I do this?
Some possible ideas I have:
Create a new Node which, every time that one of your followers makes a post, they will be added beneath your UID with a timeStamp. So When I fetch I loop through this FollowersWhoCreatedRecently for each UID and only do so for the first 10
Problems I see with the above solution is that if a user were to have a millions of people following them this would be horribly slow when it comes to updating every single one of those million
I have found this which seems like it may be of use. How could I use this?
My DB structure for posts is as follows
Post
UID
postID
Media
media
image: URL
Based in a follower structure like:
WhoFollowsMeNode/UID/uid: true
I would have to, every time a user posts, loop through this list where for each user I would add the post to there timeLine... That seems undoable, and yet that what it seems they are doing here.
On Realtime Database, you can make use of limitToLast() method, you can then pass how many elements you want to bring, this method will fetch the last information that has been added in a node, since the documents are ordered with a timestamp, if you fetch them with limitToLast(10) you can get the last 10 posts of a user.
If you are working with a List of posts, you can invert the list when showing it to the user, doing this, you will see the most recent data first and the old data below.

How do I efficiently find if one set of nodes has elements contained in another in Firebase?

I am building a social media database schema, in which I have users, followers, tags and posts. To conform to the firebase model I have flattened the structure as suggested in the firebase documentation as seen below. The issue that I am struggling with is when a user selects a tag and sees a bunch of posts from the tagPosts table all related by tag returned, I would then like to show the posts created by the current users followers first.
In SQL this would be done with an inline query checking the users followers, against the posts returned by a specific tag.
However in firebase I am not sure how do this without downloading all the posts contained under the tagID node in tagPosts and checking through each post's creator against the node of Followers for the current user userID. This operation could easily grow out of hand for 100s of posts amongst 100s of users. Ive tried modeling off of this answer, How do I check if a firebase database value exists? and this article From SQL to Firebase — How to structure the DB for a social network app. Am I poorly structuring the data how do I fix this thank you so much.
`
Users-
-userID1
-misc. userData
-userID2
-misc. userData
Followers-
-userID1
-userIDOfFollower1
-userIDOfFollower2
Following-
-userID1
-userIDOfFollower1
-userIDOfFollower2
Posts-
-postID1
-userIDFromCreator
-misc. PostData
Tags-
-tagID1
-misc. TagData
TagsUsers
-tagID1
-userID1
-userID2
TagsPosts
-tagID1
-postID1
-postID2
Edits-Thank you Frank
In our storyboard flow we plan to have a user see a wall of tags determined by constantly updating popular score based on properties of the tag and where we predict the user may have interest. The user will then select a tag and see posts related to that tag, from those posts I would like to show the posts from a users followers before those of everyone else who’s post falls in the category of a specified tag.
I have considered two possibilities either I optimize on reads in which I would have to keep track of every time a users follower posts to a tag and record the tagID along with the postID in a node for every follower a user has who posted in a special node of FollowersTags which would have a structure of listing for each userID a list of users and the all the followers of a user posted to which would become 100s of writes for each post created directly proportional to the number of followers a friend has.
*creates a list of posts to a specific tag made by followers
FollowersTags
-userID1_tagID1(composite key)
-postID1
-postID2
-postID3
-postID4
-userID1_tagID2
-postID1
-postID2
-postID3
-postID4
Or I could optimize on writes as tried above, which presents us with our current predicament of having to perform a query 100s of times directly proportional to the number of posts in a tag.
Is there any way around these two options which of the two is the better approach.
Unfortunately I would not be able to predict the posts displayed to the user before they select a tag.
In the Firebase Realtime Database, I typically model the data in the database to what I show on the screen. So if you have a "wall" of recent, relevant posts for each user, consider modeling precisely that in your database: a list of recent, relevant posts (or post IDs) for each user.
UserWalls
userID1
"timestamp_or_push_id": "postId1"
"timestamp_or_push_id": "postId2"
userID2
"timestamp_or_push_id": "postId1"
"timestamp_or_push_id": "postId3"
While the problem of determining what to show remains the same, with this database model it's now a write-time problem, instead of a read-time problem.

Resources