简体   繁体   中英

How to display a document with its subcollections from Firestore in a RecyclerView with Android?

This is what my Firestore database looks like:

在此处输入图像描述

I have a RecyclerView which displays a list of posts. But I am not able to retrieve a document with its subcollections and put it inside an object. When I submit a list of posts in my RecyclerView , I want each post to already have its Likes and Comments.

I use AsyncTask to do the background work of querying all the posts of the user. After the AsyncTask is done, it will submit the List of posts to the RecyclerView. (Still doesn't work)

In the code below, I'm calling all the Posts of the user and then getting the "Likes" of each post. I have put a while loop inside each post so that I can wait for it to finish querying the Likes before proceeding to the next Post snapshot

doInBackground()

final List<Post> postList = new ArrayList<>();
// -- GET all the posts of the user
feedsCollection.document(documentID).collection("Posts").get()
    .addOnSuccessListener(new OnSuccessListener<QuerySnapshot>() {
        @Override
        public void onSuccess(QuerySnapshot queryDocumentSnapshots) {

            for(final DocumentSnapshot documentSnapshot1 : queryDocumentSnapshots){
                final Post post = documentSnapshot1.toObject(Post.class);

                // Finish getting the likes&comments before proceeding
                while(post.isStillLoading()){
                    // -- GET Likes of each post
                    db.collection("FeedsCollection").document(documentID).collection("Posts")
                            .document(documentSnapshot1.getId()).collection("Likes").get()

                            .addOnSuccessListener(new OnSuccessListener<QuerySnapshot>() {
                                @Override
                                public void onSuccess(QuerySnapshot queryDocumentSnapshots) {

                                    List<Like> likeList = new ArrayList<>();
                                    for(DocumentSnapshot likeSnapshot : queryDocumentSnapshots){
                                        Like like = likeSnapshot.toObject(Like.class);
                                        likeList.add(like);
                                    }
                                    post.setLikes(likeList);
                                    post.setStillLoading(false);

                                }
                            });
                    // -- GET comments code
                }
                postList.add(post);
            }
        }
    });
return postList;

onPostExecute()

    protected void onPostExecute(List<Post> postList) {
                super.onPostExecute(postList);
    
                adapter.submitData(postList);
    
    
            }

These are the things I've tried:

  • I tried having multiple viewtypes in my recyclerview, so that if the list is still empty, it displays "No items". And then when the AsyncTask finish, it will re-submit a list to the recyclerview.
  • I tried to use FirestoreRecyclerAdapter but I've read that its queries are shallow so it can't get the Likes and Comments subcollections of each post document altogether.

Any other workaround for this?

But I am not able to retrieve a document with its subcollections and put it inside an object.

There's no way you can achieve this. The queries in Firestore are shallow, so it is allowed to only get documents from the collection that the query is run against. Furthermore, there is no way you can get a document together with the nested subcollections in a single go. You can get the document and then run separate queries for each and every subcollection.

Another possible solution might be to use Firebase Realtime Database , where when you download a node, you download it together with all the data that exist beneath that node.

I use AsyncTask to do the background work of querying all the posts of the user.

The Cloud Firestore client already runs all.network operations in a background thread. This means that all operations take place without blocking your main thread. Putting it in an AsyncTask does not give any additional benefits.

If you have data in multiple collections, even nested collections, you will have to perform multiple queries to get all that data. It won't be possible with just a single query. You can certainly implement what you want, it will just be significantly more complex to do so.

It will require one query to get all the documents in PostsCollection, then more queries for each of the subcollections nested under Comments and Likes for each of the posts.

Switching to Realtime Database as Alex suggests might not be a good idea. You will lose a lot of more complex querying capability just to get deep queries, and you might not even want fully deep queries all the time, as that could be more expensive overall.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM