Flutter.io (Dart) - How to count items returned from Firebase query that meet certain conditions

1,611

I think you are not hitting the problem from the proper point of view, plus the title is misleading.

You might not intend to count the widget shown on the screen, but rather count a subset of Firebase database entries that fit some conditions. This makes a big difference in Flutter, since counting widgets involves the the render tree, the layouts and graphics in general, while it looks you want to address a data problem.

If I am right then you might consider having an index in your db keeping track of the number of blue items and listen to it in another streambuilder.

Long story short, you might want to keep a map< id, blueness >, update each element at build time, and iterate over the map whenever required to count.

// somewhere in your outer scope
Map<int, bool> _bluenessMap = new Map<int, bool>();
  return new StreamBuilder<int>(
    stream: subscribeMyThings(thing.id),
    builder: (context, thingsSnapshot) {
        return new FirebaseAnimatedList(
          query: getThings(thing.id),
          itemBuilder: (context, snapshot, animation, index) {
            return new ReactiveWidget<int>(
              reactiveRef: getThingBlueness(snapshot.key),
              widgetBuilder: (checkBlueness) {
                // code to check blueness here
                // ----------------------------
                // before return let us update the map
                _bluenessMap[thing.id] = thingIsBlue
                // ----------------------------
                // if Thing is blue, place empty container
                if (thingIsBlue) {
                  return new Container();
                }
                // or, if Thing is NOT blue
                return new Thing(thing.id);
                );
              },
            );
        );
      }
  // call me when you want to count
  int fancyBlueCounter(){
      int result = 0;
      for(bool isBlue in _bluenessMap.values){
        if(isBlue) result += 1;
      }
      return result;
  }

Edit

Since the author of the question confirmed it is a "data problem", I feel like suggesting another (maybe better) way to address it.

Aggregates or Indexes are (in my opinion) the proper way to solve your problem. Anytime someone touches a Thing depending on its blueness it refreshes a purposefully created aggregate in the DB (actually also a simple data entry count). You can do this either following any function editing Things with a transaction updating the blue count, or with cloud functions (see doc here) listening for changes events (creation, deletion, and edit) and updating the count as well.

Share:
1,611
Deborah
Author by

Deborah

I am a Senior-level UI and UX Designer and Front End Developer with significant start-up experience, online SAAS experience and responsive web application experience. I have been the Lead Product Designer for web apps, hybrid apps and mobile apps.

Updated on November 22, 2022

Comments

  • Deborah
    Deborah about 1 month

    In a screen, a Firebase list has logic applied to

    1. reactively detect blueness of widgets
    2. hide blue widgets
    3. show non-blue widgets

    I want to count the blue widgets.

    What is the best way to do this?

    return new StreamBuilder<int>(
        stream: subscribeMyThings(thing.id),
        builder: (context, thingsSnapshot) {
            return new FirebaseAnimatedList(
              query: getThings(thing.id),
              itemBuilder: (context, snapshot, animation, index) {
                return new ReactiveWidget<int>(
                  reactiveRef: getThingBlueness(snapshot.key),
                  widgetBuilder: (checkBlueness) {
                    // code to check blueness here
                    // if Thing is blue, place empty container
                    if (thingIsBlue) {
                      return new Container();
                      // *** how do I count these??? ***
                    }
                    // or, if Thing is NOT blue
                    return new Thing(thing.id);
                    );
                  },
                );
            );
          }
    
  • Deborah
    Deborah almost 5 years
    You are exactly right, I want to count a subset of data that meet some conditions. This looks like it should work beautifully, but I could not get it working. I'll keep trying and if I can get it running correctly I'll mark as answer.
  • Deborah
    Deborah almost 5 years
    Edited title and question to better reflect this.
  • Fabio Veronese almost 5 years
    @Deborah as I mentioned it is difficult to provide a minimal working example with just the code you provided. Anyhow I'll be glad to help if I can, feel free to give some more details concerning the result.
  • Fabio Veronese almost 5 years
    @Deborah please check also the "data" solution as in the updated answer.
  • Larry King
    Larry King almost 5 years
    I agree completely with @fabio-veronese. I came across your exact issue in my flutter app working with Firestore and ended up creating a collection of document ids adjacent to my main collection, i.e. the id of every doc in my main collection is placed in a separate id collection. I just had to put in some overhead in the app to manage/use the id's collection parallel to the primary Firestore stream. Works just fine. I thought Firebase real time database might work better, but I think it will be similar in terms of what you and I are trying to do. Good luck!