Home > Mobile >  From a `FutureBuilder`, my future never returns data
From a `FutureBuilder`, my future never returns data

Time:01-02

In a future builder, I use the following future that should return the number of documents (The collection stores "seen" event of an ad detailed view):


 /// Stores and returns the document [id].
  static Future<int> getCount({required String? adId}) {
    if (adId == null) return Future<int>.value(0);

    // = Actually store the document
    final c = FirebaseFirestore.instance
        .collection(collectionName)
        .where("adId", isEqualTo: adId)
        .snapshots()
        .length;

    return c;
  }

The FutureBuilder:

                    FutureBuilder(
                      future: ClassifiedAdSeen.getCount(adId: ad.id),
                      builder: (context, snapshot) {
                        if (snapshot.hasError) {
                          return const Icon(Icons.error);
                        } else if (!snapshot.hasData) {
                          return const CircularProgressIndicator();
                        }
                        final count = snapshot.data ?? "—";
                        return Text("$count");
                      }),

But it never hasData nor hasError, the spinner keeps on progressing.

Any idea Where the issue is, please?

[UPDATE]

By fetching the documents, I get the completion and the count with no problem. But fetching the documents is a waste of memory and bandwidth, isn't it?

So what would be the best way of fetching only the document count?


/// Stores and returns the document [id].
  static Future<int> getCount({required String? adId}) async {
    if (adId == null) return 0;

    // = Actually store the document
    final c = await FirebaseFirestore.instance
        .collection(collectionName)
        .where("adId", isEqualTo: adId)
        .get(); 

    return c.size;
  }

CodePudding user response:

In your case, which is getting only the length of documents from your query, there is also a count() method that returns an AggregateQuery, which you don't get billed for, it returns only the length of the documents, nothing else.

Give it a try:

/// Stores and returns the document [id].
  static Future<int> getCount({required String? adId}) async {
    if (adId == null) return 0;

    // = Actually store the document
    final c = await FirebaseFirestore.instance
        .collection(collectionName)
        .where("adId", isEqualTo: adId)
        .count()
        .get(); 

    return c.count;
  }

CodePudding user response:

The snapshots() returns a Stream, since you said that you want just to get the number of the documents on your query, consider using get(), in addition that you need an async/await in your method, then return the QuerySnapshot in your Future method, then call the length on it's docs property :

  static Future<QuerySnapshot> getQuerySnapshot({required String? adId})  async {
    
    final c = await FirebaseFirestore.instance
        .collection(collectionName)
        .where("adId", isEqualTo: adId)
        .get();    
    return c;
  }

FutureBuilder :

FutureBuilder<QuerySnapshot>(
              future: ClassifiedAdSeen.getQuerySnapshot(adId: ad.id),
              builder: (_, AsyncSnapshot<QuerySnapshot> snapshot) {
                if (snapshot.hasError) {
                  return const Icon(Icons.error);
                } else if (snapshot.connectionState == ConnectionState.waiting) {
                  return const CircularProgressIndicator();
                }
                final count = snapshot.data.docs.length ?? "—"; // like this
                return Text("$count");
              }),
  • Related