Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to retrieve documents of a sub collection in Firestore?

I have a db with structure like in the image below: enter image description here

Here, I need to have multiple brands, and also multiple sub brands under each brand. I tried with 'maps' before, but it was really messy and also learned that it's better to have multiple documents. I am very new to this and has been struggling with it for 3-4 days now. Any help would be much appreciated.

  firebaseFirestore.collection("Coffee").addSnapshotListener(new EventListener<QuerySnapshot>() {
        @Override
        public void onEvent(QuerySnapshot documentSnapshots, FirebaseFirestoreException e) {
            if (e != null) {
                Log.d(TAB, "Error : " + e.getMessage());
            }
            for (DocumentChange doc : documentSnapshots.getDocumentChanges()) {
                if (doc.getType() == DocumentChange.Type.ADDED) {
                    Log.d("Brand Name: ",doc.getDocument().getId());

                  //  how to retrieve documents of subCollection here? something like doc.getDocument().collection??

                }

            }

        }
    });

Thank you.

like image 338
nandu Avatar asked Mar 18 '18 17:03

nandu


2 Answers

This is really simple and easy try this.

 firebaseFirestore.collection("Coffee").addSnapshotListener(new EventListener<QuerySnapshot>() {
        @Override
        public void onEvent(QuerySnapshot documentSnapshots, FirebaseFirestoreException e) {
            if (e != null) {
                Log.d("", "Error : " + e.getMessage());
            }
            for (DocumentChange doc : documentSnapshots.getDocumentChanges()) {
                if (doc.getType() == DocumentChange.Type.ADDED) {
                    Log.d("Brand Name: ", doc.getDocument().getId());
                    doc.getDocument().getReference().collection("SubBrands").addSnapshotListener(new EventListener<QuerySnapshot>() {
                        @Override
                        public void onEvent(QuerySnapshot documentSnapshots, FirebaseFirestoreException e) {
                            if (e != null) {
                                Log.d("", "Error : " + e.getMessage());
                            }

                            for (DocumentChange doc : documentSnapshots.getDocumentChanges()) {
                                if (doc.getType() == DocumentChange.Type.ADDED) {
                                    Log.d("SubBrands Name: ", doc.getDocument().getId());
                                }
                            }

                        }
                    });
                }

            }
        }});

Note: i have updated the answer. It is obvious that you can't fetch sub collections within the collection's document with a single request.

like image 136
Nouman Ch Avatar answered Sep 19 '22 20:09

Nouman Ch


I see that is already an accepted answer but I want to provide you a more elegant way of structuring your database. This means that you'll also able to retrieve the data more easily. Before that, as I understand from your question, you only want to retrieve data but in order to achieve this, just use a get() call. addSnapshotListener() is used to retrieve real time data.

This is the database structure that I suggest you use for your app:

Firestore-root
   |
   --- coffee (collection)
         |
         --- coffeeId (document)
                |
                --- coffeeBrand: "Nescafe"
                |
                --- coffeeSubBrand: "Sunrise"
                |
                --- coffeeName: "CoffeeName"
                |
                --- quantity
                       |
                       --- 50g: true
                       |
                       --- 100g: true
                       |
                       --- 150g: true

While Nouman Ch's code might work on your actual database structure, this new structure will provide you the ability to avoid nested loops. To get all the coffees, just use the following code:

FirebaseFirestore rootRef = FirebaseFirestore.getInstance();
CollectionReference coffeeRef = rootRef.collection("coffee");
coffeeRef.get().addOnCompleteListener(new OnCompleteListener<QuerySnapshot>() {
    @Override
    public void onComplete(@NonNull Task<QuerySnapshot> task) {
        if (task.isSuccessful()) {
            for (DocumentSnapshot document : task.getResult()) {
                String coffeeName = document.getString("coffeeName");
                Log.d("TAG", coffeeName);
            }
        }
    }
});

If you want to display only the Nescafe coffee, instead of using a CollectionReference, you need to use a Query:

Query query = coffeeRef.whereEqualTo("coffeeBrand", "Nescafe");

If you want to display only the coffee SubBrands then use the following Query:

Query query = coffeeRef.whereEqualTo("coffeeSubBrand", "Sunrise");

If you want to display the coffees Brands and SubBrands, you can chain methods like this:

Query query = coffeeRef
    .whereEqualTo("coffeeSubBrand", "Sunrise")
    .whereEqualTo("coffeeBrand", "Nescafe");

If you want to display only the coffee with the quantity of 100g, then just use the following query:

Query query = coffeeRef.whereEqualTo("quantity.100g", true);

If you want to learn more about Cloud Firestore database structures, you can take a look on one of my tutorials.

like image 20
Alex Mamo Avatar answered Sep 18 '22 20:09

Alex Mamo