Android Firestore subcollections into RecyclerView



I am currently working on a Rental Car app in Java Android Studio. For the project database, I am using Cloud Firestore. My database is structured like so:

collection

Subcollection: subcollection

The first image is represented by the collection of Cars with multiple documents with random ID (each represents a car). Every car has a unique subcollection called bookings where are saved in random ID documents details about bookings made to that specific car (the second image is represented by an example of a booking subcollection).

I am currently working at a “Booking history” section. There, I want to put the current user’s booking history (highlighted with red in the second image) in a RecyclerView. I know how to iterate between all cars and their subcollection and put and if(bookedBy == currentUser) condition to obtain only the cars booked by the current user.

But my question is: How can I save those in a RecyclerView? I want to save data highlighted in red (second image) in the RecyclerView if our previous condition is met. I don’t know what query to put in the Firestore adapter. I was thinking about saving all the cars booked by the user and their dates in an object or something like this but I can’t figure it out. Can anyone help me, please?

Thank you!

Answer

According to your database structure, which looks like this:

Firestore-root
  |
  --- Cars (collection)
       |
       --- $cardId (document)
             |
             --- bookings (collection)
                  |
                  --- $bookingId
                        |
                        --- bookedBy: "bogdanmaris11@yahoo.com"
                        |
                        --- endDate: 31 May, 2021...
                        |
                        --- finalPrice: 1998
                        |
                        --- startDate: 30 May, 2021...

To get all the bookings that correspond to a specific user, a Cloud Firestore collection group query is required. This query looks like this:

FirebaseFirestore rootRef = FirebaseFirestore.getInstance();
Query queryByEmail = rootRef.collectionGroup("bookings").whereEqualTo("bookedBy", "bogdanmaris11@yahoo.com");
queryByEmail.get().addOnCompleteListener(/* ... /*);

There are three things to notice. To get the desired results from this query, you might check the email address, as you might have a typo, bogdanmari(u)s11@yahoo.com, where the “u” is missing. Second, it’s best to filter the users based on their UIDs and not based on their email addresses, because a user can change the email address at any time, while the UID will always remain the same. And the third one, as I understand, you intend to use the Firebase-UI library, which is good. In this case, the “queryByEmail” should be passed to FirestoreRecyclerOptions.Builder’s setQuery() method. However, there might be an issue, because each query requires an index, and the numbers of indexes are limited in Firestore.

According to what you wrote:

I was thinking about saving all the cars booked by the user and their dates in an object or something like this but I can’t figure it out.

That’s a great idea. That’s not about an object, as it more about a sub-collection or a new top-level collection, where you can nest all bookings that correspond to a specific user. In the first case, your schema will look like this:

Firestore-root
  |
  --- bookings (collection)
       |
       --- $uid (document) //Not email address
             |
             --- userBookings (collection)
                  |
                  --- $bookingId
                        |
                        --- carId: "YI1J ... VSm0"
                        |
                        --- endDate: 31 May, 2021...
                        |
                        --- finalPrice: 1998
                        |
                        --- startDate: 30 May, 2021...

Where there is no need for any email address in the Booking object, however a “cardId” is required, if you need the car data. To get all booking of a single user, the following reference is needed:

String uid = FirebaseAuth.getInstance().getCurrentUser().getUid();
FirebaseFirestore rootRef = FirebaseFirestore.getInstance();
CollectionReference userBookingsRef = rootRef.collection("bookings").document(uid).collection("userBookings");
userBookingsRef.get().addOnCompleteListener(/* ... /*);

And in the second:

Firestore-root
  |
  --- allBookings (collection)
        |
        --- $bookingId
               |
               --- bookedBy: "longUid"
               |
               --- carId: "YI1J ... VSm0"
               |
               --- endDate: 31 May, 2021...
               |
               --- finalPrice: 1998
               |
               --- startDate: 30 May, 2021...

Where is a simple query (without index) will do the trick:

String uid = FirebaseAuth.getInstance().getCurrentUser().getUid();
FirebaseFirestore rootRef = FirebaseFirestore.getInstance();
Query QueryByUid = rootRef.collection("allBookings").whereEqualTo("uid", uid);
QueryByUid.get().addOnCompleteListener(/* ... /*);

Pass the first reference or this Query to your “FirestoreRecyclerAdapter” and that’s pretty much of it.



Source: stackoverflow