Deborah
Deborah

Reputation: 4575

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

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

Upvotes: 3

Views: 1900

Answers (1)

Fabio Veronese
Fabio Veronese

Reputation: 8360

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.

Upvotes: 3

Related Questions