Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Working with nested single queries in Firestore

Recently I moved my data model from Firebase to Firestore. All my code is working, but I'm having some ugly troubles regarding my nested queries for retrieve some data. Here is the point:

Right now my data model for this part looks like this(Yes! Another followers/feed example):

{
  "Users": { //Collection
    "UserId1" : { //Document
      "Feed" : { //Subcollection of Id of posts from users this user Follow
        "PostId1" : { //Document
          "timeStamp" : "SomeDate"
        },
        "PostId2" : {
          "timeStamp" : "SomeDate"
        },
        "PostId3" : {
          "timeStamp" : "SomeDate"
        }
      }
      //Some data
    }
  },
  "Posts":{ //Collection
    "PostId1":{ //Document
      "Comments" :{ //Subcollection
        "commentId" : { //Document
          "authorId": "UserId1"
          //comentsData
        }
      },
      "Likes" : { //Subcollection
        "UserId1" : { //Document
          "liked" : true
        }       
      }
    }
  }
}

My problem is that for retrieve the Posts of the feed of an user I should query in the next way:

  • Get the last X documents orderer by timeStamp from my Feed

feedCol(userId).orderBy(CREATION_DATE, Query.Direction.DESCENDING).limit(limit)

  • After that I should do a single query of each post retrieved from the list: workoutPostCol.document(postId)

  • Now I have the data of each post, but I want shot the username, picture, points.. etc of the author, which is in a different Document, so, again I should do another single query for each authorId retrieved in the list of posts userSocial(userId).document(toId)

  • Finally, and not less important, I need to know if my current user already liked that post, so I need to do a single query for each post(again) and check if my userId is inside posts/likes/{userId}

Right now everything is working, but thinking that the price of Firestore is depending of the number of database calls, and also that it doesn't make my queries more simple, I don't know if it's just that my data model is not good for this kind of database and I should move to normal SQL or just back to Firebase again.

Note: I know that EVERYTHING, would be a lot more easier moving this subcollections of likes, feed, etc to arraylists inside my user or post documents, but the limit of a Document is 1MB and if this grow to much, It will crash in the future. In other hand Firestore doesnt allow subdocument queries(yet) or an OR clause using multiple whereEqualTo.

I have read a lot of posts from users who have problems looking for a simple way to store this kind of ID's relationship to make joins and queries in their Collections, use Arraylists would be awesome, but the limit of 1MB limit it to much.

Hope that someone will be able to clarify this, or at least teach me something new; maybe my model is just crap and there is a simple and easiest way to do this? Or maybe my model is not possible for a non-sql database.

like image 632
Francisco Durdin Garcia Avatar asked Oct 13 '17 07:10

Francisco Durdin Garcia


People also ask

How do I query a nested object in firestore?

Answers 2 : of How to query nested objects in firestore However, by restructuring the data in the document, a query can be made to work where only one field is known, like a user identifier (uid). Here's the query: uid = 'user4'; collectionQuery = collectionReference.

How do I query multiple collections in firestore?

Firestore does not have the concept of server-side joins or projections across collections. Each query or document read can only take data from a single collection, or from all collections that have the same name with collection group queries.

Can firestore update multiple documents matching a condition using one query?

Cloud Firestore does not support the equivalent of SQL's update queries.

Can two documents have the same ID in firestore?

You cannot have several documents with the same ID in one Collection: a document ID must be unique across a collection.


1 Answers

Not 100% sure if this solves the problem entirely, since there may be edge cases for your usage. But with a 5 min quick thinking, I feel like the following could solve your problem :

You can consider using a model similar to Instagram's. If my memory serves me well, what they use is an events-based collection. By events in this specific context I mean all actions the user takes. So a comment is an event, a like is an event etc.

This would make it so that you'll need three main collections in total.

users
-- userID1
---- userdata (profile pic, bio etc.)
---- postsByUser : [postID1, postID2]
---- followedBy : [userID2, ... ]
---- following : [userID2, ... ]
-- userID2
---- userdata (profile pic, bio etc.)


posts
-- postID1 (timestamp, so it's sortable)
---- contents
---- author : userID1
---- authorPic : authorPicUrl
---- authorPoints : 12345
---- taggedUsers : []
---- comments
------ comment1 : { copy of comment event }
---- likes : [userID1, userID2]
-- postID2 (timestamp)
---- contents
... 


events
-- eventID1
---- type : comment
---- timestamp
---- byWhom : userID
---- toWhichPost : postID
---- contents : comment-text
-- eventID2
---- type : like
---- timestamp
---- byWhom : userID
---- toWhichPost : postID

For your user-bio page, you would query users.

For the news feed you would query posts for all posts by userIDs your user is following in the last 1 day (or any given timespan),

For the activity feed page (comments / likes etc.) you would query events that are relevant to your userID limited to the last 1 day (or any given timespan)

Finally query the next days for posts / events as the user scrolls (or if there's no new activity in those days)

Again, this is merely a quick thought, I know the elders of SOF have a habit of crucifying these usually, so forgive me fellow members of SOF if this answer has flaws :)

Hope it helps Francisco,

Good luck!

like image 93
johnozbay Avatar answered Oct 03 '22 12:10

johnozbay