skip to Main Content

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;
  }

2

Answers


  1. 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");
                  }),
    
    Login or Signup to reply.
  2. 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;
      }
    
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search