Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Reduce number of read in Firestore Android

I want to reduce number of reads in order to get Question's detail from QuestionCollection (Array of Questions) .

My app works like a part of stackoverflow.

I want to show how many likes, views and comments do a question have . So in order to handle this I created multiple collection like

QuestionCollection

  • ID
  • Title
  • DateCreated

CommentCollection

  • ID
  • Comment
  • DateCreated

QuestionLikes

  • QuestionID
  • UserID

QuestionViews

  • QuestionID
  • UserID

QuestionTAG

  • QuestionID
  • TagID

I thought that CommentCollection (comments) only belongs to a question. So I am thinking of incorporating in QuestionCollection like an array(s) or collection(But it requires another read hit). which one is better ?

And I think of adding two variable's(totalViews,totalLikes) to QuestionCollection. But each time I must have to check whether this question is liked by this user or view by this user.

Give me a suggestion or an alternative so I can have the least hit to fetch question details.

Edit

For Showing View Count I iterate and count QuestionViews Collection where questionID == myQuestionID

For Showing Likes Count I iterate and count QuestionLikes Collection where questionID == myQuestionID

why I don't add it to QuestionCollection? Because I want to show most Viewed and most like question like stackoverflow. If i add it to QuestionCollection How could I know the most like and most Viewed question.

like image 707
Zar E Ahmer Avatar asked Aug 27 '18 11:08

Zar E Ahmer


People also ask

How do you reduce the number of read operations in cloud firestore?

This means that Cloud Firestore will try to retrieve an up-to-date (server-retrieved) snapshot, but fall back to returning cached data if the server can't be reached. This is how we can reduce the number of reads in Cloud Firestore, by forcing the SDK to use only the offline cache and get the data only upon request.

Why are my reads so high firestore?

If you leave the console open on a collection or document with busy write activity then the Firebase console will automatically read the changes that update the console's display. Most of the time this is the reason for unexpected high reads.

How many reads can firestore handle?

10 for single-document requests and query requests. 20 for multi-document reads, transactions, and batched writes. The previous limit of 10 also applies to each operation.

What counts as a read on firestore?

When you listen to the results of a query, you are charged for a read each time a document in the result set is added or updated. You are also charged for a read when a document is removed from the result set because the document has changed. (In contrast, when a document is deleted, you are not charged for a read.)


1 Answers

The most efficient schema I can think of, is the following:

Firestore-root
    |
    --- questions (collections)
    |     |
    |     --- questionId (document)
    |            |
    |            --- questionId: "02cubnmO1wqyz6yKg571"
    |            |
    |            --- title: "Question Title"
    |            |
    |            --- date: August 27, 2018 at 6:16:58 PM UTC+3
    |            |
    |            --- comments (colletion)
    |            |     |
    |            |     --- commentId
    |            |            |
    |            |            ---commentId: "5aoCfqt2w8N8jtQ53R8f"
    |            |            |
    |            |            ---comment: "My Comment"
    |            |            |
    |            |            ---date: August 27, 2018 at 6:18:28 PM UTC+3
    |            |
    |            --- likes (colletion)
    |            |     |
    |            |     --- likeId (document)
    |            |            |
    |            |            --- userId: true
    |            |
    |            --- views (colletion)
    |            |     |
    |            |     --- viewId (document)
    |            |            |
    |            |            --- userId: true
    |            |
    |            --- tags ["tagId", "tagId"]
    |
    --- tags (collections)
          |
          --- tagId (document)
                |
                --- tagId: "yR8iLzdBdylFkSzg1k4K"
                |
                --- tagName: "Tag Name"

In which the comments, likes and views are colletions under questionId document. Unlike in Firebase real-time database where to display a list of question you would have been downloaded the entire question object, in Cloud Firestore this is not an issue anymore. So to avoid querying using a where methods, you can simply get a specific question like this:

FirebaseFirestore rootRef = FirebaseFirestore.getInstance();
DocumentReference questionIdRef = rootRef.collection("questions").document(questionId);
questionIdRef.get().addOnCompleteListener(/* ... */);

Because you can have hundreds, thousands or even more comments, likes and views to a single question, storing the data into an array will not help you. According to the official documentation:

Cloud Firestore is optimized for storing large collections of small documents.

For example, to get all the comments of a specific question, you can use the following query:

Query query = rootRef.collection("questions/"+questionId+"comments").orderBy("date", Query.Direction.DESCENDING);

Because a question can have only a few tags, you can simply use an array. To get all questions with a specific tag, you can use the following query:

Query query = rootRef.collection("questions/"+questionId+"tags").whereArrayContains("tags", tagId);

One more thing to remember, even if tags object is stored in the database as an array, document.get("tags") will return an ArrayList and not an array.

If you also want to count the number of likes or any other number of documents within a collection, please see my answer from this post.

Edit:

According to your comments:

If I want to show the most liked question of all to a user. How could I do this?

You should add the number of likes as a property inside the question object and then you can query the database according to it like this:

Query query = rootRef.collection("questions").orderBy("numberOfLikes", Query.Direction.DESCENDING);

According to this you can also store the number of likes in the Firebase real-time database and you can increase/decrease it using Firebase Transactions.

secondly if I want to show all the question related to a tag like mathematics (show all question which have mathematics tag) ??

As also mentioned above you can take atvantage of the whereArrayContains method. You can also store the tags as String and not as id. For that, you need to change this structure:

--- tags ["tagId", "tagId"]

to

--- tags ["mathematics", "chemistry"]

And the code should look like this:

Query query = rootRef.collection("questions/"+questionId+"tags").whereArrayContains("tags", "mathematics");

the statement (userId: true) saves a lot of data repetition

Yes it does.

like image 85
Alex Mamo Avatar answered Sep 17 '22 21:09

Alex Mamo