Rafael Canuto
Rafael Canuto

Reputation: 95

How to get all documents that are inside of a collection that is inside of another collection on Firestore?

Well, I'm trying to build a function that when I click in a favorite icon I am choosing a place as one of my favorite places. And if I want to see my favorite places, I need just go to the favorite page that should return all my favorite places. I have two favorite places stored on my firestore. When I'm trying to get them, returns nothing... And that's the problem.

Each favorite document, contains fields like city, image etc. Here's my database: https://i.sstatic.net/k8d4O.png

import 'package:cloud_firestore/cloud_firestore.dart';
import 'package:firebase_auth/firebase_auth.dart';
import 'package:flutter/material.dart';

class Favorites extends StatefulWidget {
  @override
  _FavoritesState createState() => _FavoritesState();
}

class _FavoritesState extends State<Favorites> {
  @override
  Widget build(BuildContext context) {
    double width = MediaQuery.of(context).size.width;
    double height = MediaQuery.of(context).size.height;

    dynamic loadFavorites() async{
      final FirebaseUser user = await FirebaseAuth.instance.currentUser();
      final dynamic userUid = user.uid;
      return userUid;
    }

    dynamic document = loadFavorites();

    return Scaffold(
      body: SingleChildScrollView(
        child: Column(
          children: <Widget>[
            Padding(
              padding: EdgeInsets.only(top: 30.0, bottom: 5.0),
              child: Text("Favoritos", 
              style: TextStyle(fontSize: 20),
              textAlign: TextAlign.center, 
              ),
            ),
            Container(
              child: FutureBuilder<QuerySnapshot>(
                future: Firestore.instance.collection("users").document(document.toString()).collection("favorites").getDocuments(),
                builder: (context, snapshot){
                  if(!snapshot.hasData){
                    return Center(child: CircularProgressIndicator());
                  }else{
                    return snapshot.data.documents.isEmpty ? Center(child: Text("Nenhum favorito escolhido.")) : ListView.builder(
                      physics: const NeverScrollableScrollPhysics(),
                      scrollDirection: Axis.vertical,
                      shrinkWrap: true,
                      itemCount: snapshot.data.documents.length,
                      itemBuilder: (context, index){
                        return Container(
                          padding: EdgeInsets.all(10.0),
                          child: buildFavorite(width, height, snapshot.data.documents[index]),
                        );

                      },
                    );
                  }
                },
              ),
            ),

          ],  
        ),
      ),     
    );   
  }
  Widget buildFavorite(double width, double height, DocumentSnapshot document){
    return Container(
      padding: EdgeInsets.all(10.0),
      decoration: BoxDecoration(
        color: Colors.white,
        boxShadow: <BoxShadow>[
          BoxShadow(
            color: Colors.grey,
            offset: Offset(1.0, 1.0),
            blurRadius: 10.0,
          ),
        ],
        borderRadius: BorderRadius.circular(10.0),
      ),
      child: Stack(
        children: <Widget>[
          //Padding(padding: EdgeInsets.only(top: 100),),
          Container(
            margin: EdgeInsets.only(bottom: 20.0, left: 20.0),
            child: Text(document["title"], style: TextStyle(fontSize: 18),),
          ),

          Container(
            width: width * 0.37,
            height: height * 0.18,
            decoration: BoxDecoration(
              shape: BoxShape.rectangle,
              image: DecorationImage(
                fit: BoxFit.fill,
                image: NetworkImage(document["image"]),
              ),
              boxShadow: <BoxShadow>[
                BoxShadow(
                  color: Colors.grey,
                  offset: Offset(1.0, 1.0),
                  blurRadius: 1.0,
                ),
              ],
            ),
            margin: EdgeInsets.only(left: width * 0.60),
          ),
          Row(
            children: <Widget>[
              Container(
                margin: EdgeInsets.only(top: 30.0),
                child: Icon(Icons.location_on, color: Colors.red,),

              ),
              Container(
                margin: EdgeInsets.only(left: 10.0, top: 30.0),
                child: Text(document["text"]),
              ),

            ],
          ),
          Row(
            children: <Widget>[
              Container(
                margin: EdgeInsets.only(top: 60.0),
                child: Icon(Icons.phone, color: Colors.red),

              ),
              Container(
                margin: EdgeInsets.only(left: 10.0, top: 60.0),
                child: Text(document["phone"]),
              ),
            ],
          ),
          Row(
            children: <Widget>[
              Container(
                margin: EdgeInsets.only(top: 90.0),
                child: Icon(Icons.timer, color: Colors.red,),
              ),
              Container(
                margin: EdgeInsets.only(left: 10.0, top: 90.0),
                child: Text(document["time"]),
              ),
            ],
          ),
        ],
      ),
    );
  }
}

Upvotes: 0

Views: 48

Answers (1)

kounex
kounex

Reputation: 1715

Your Problem lies here:

future: Firestore.instance.collection("users").document(document.toString()).collection("favorites").getDocuments(),

document.toString() will return Instance of Future<dynamic> since the actual type of this variable is the return type of your loadUser() function which is Future<dynamic> and the toString() method of objects is usually Instance of CLASS_NAME. Generally I strongly recommend you to make use of the type safety of dart by always using explicit types instead of dynamic! Errors occuring while using types indicate that something you are trying is not correct and better helps to understand what kind of value is to be expected.

You are trying to retrieve the userUid to use it inside your FutureBuilder but unfortunately this function needs to be async since you have to get it from Firebase. The surrounding function (build of your Widget) is not async. Therefore you can't resolve the loadUser() function as you intend to. To fix this issue you need to extract the userUid and favorites retrieval outside your build function - let me show you an example:

Future<QuerySnapshot> getFavoritesFromUser() async {
  FirebaseUser user = await FirebaseAuth.instance.currentUser();
  final String userUid = user.uid;
  
  return Firestore.instance.collection("users").document(userUid).collection("favorites").getDocuments();
}

@override
Widget build(BuildContext context) {
  ...
  Container(
    child: FutureBuilder<QuerySnapshot>(
      future: this.getFavoritesFromUser()
      ...
  

Upvotes: 2

Related Questions