2

I am building an where when the user logs in to the app, it shows all the user's information that are also registered on the app. With my init fetch method that fetches all the information it uses a large amount of read which came up to 1.3k reads from a few days of testing whilst there being only 4 users registered. which is unusually high.

My fetch method which fetches the users information from firestore

void loadUserProfiles() async {
    var firebaseUser = await FirebaseAuth.instance.currentUser();
    List<String> tempUsers = List<String>();
    List<String> tempNames = List<String>();
    List<String> tempImages = List<String>();

    imageUrl.clear();
    names.clear();
    userId.clear();

    tempUsers.clear();
    tempNames.clear();
    tempImages.clear();
    setState(() {
      isLoading = true; //Data is loading
    });

    // Adds all the values of each user from firestore to their list to compare
    await firestoreInstance
        .collection("users")
        .getDocuments()
        .then((QuerySnapshot snapshot) async {
      snapshot.documents.forEach((f) async {
        if (f.documentID != firebaseUser.uid) {
          tempUsers.add(f.data['userid']);
          tempNames.add(f.data['name']);
          tempImages.add(f.data['images'][0]);
        }
      });
    });

    // Adds user to list to load to user cards if doesnt exist in liked users firestore
    for (int i = 0; i < tempUsers.length; i++) {
      await firestoreInstance
          .collection("users")
          .document(firebaseUser.uid)
          .collection("liked_users")
          .document(tempUsers[i])
          .get()
          .then((value) async {
        if (!value.exists) {
          userId.add(tempUsers[i]);
          names.add(tempNames[i]);
          imageUrl.add(tempImages[i]);
        }
      });
    }

    setState(() {
      isLoading = false; //Data has loaded
    });
  }

The way i have done it is that it fetches all the data and stores them into three separate temporary lists. Then using those lists i would read through the firestore again to compare if the user's id that the current user has liked exists or not in a collection.

It also gets worse since im using a bottom nav bar and whenever that page is clicked it starts my load method again which uses more reads.

iKreateCode
  • 189
  • 3
  • 13
  • how sure are you that all the reads come from this single operation only? Seems unlikely that with a nested collection of depth 2 and 4 max entities at each level that it can multiply up to 1300 reads – VLXU Jul 03 '20 at 14:20
  • I'm sorry i should have made it more clear. I didn't mean for it come from one operation, i have been testing it for a few days now but i'm sure it shouldn't be that high with 4 users – iKreateCode Jul 03 '20 at 14:21
  • Next time, try to add more details such the number of days you’ve been testing or even a rough estimation of how many times you’ve tried to run this function – VLXU Jul 03 '20 at 14:44

1 Answers1

0

There are several things you can do:

  1. Pagination In your code getDocuments you seem to be retrieving EVERY SINGLE user. Generally, with huge collections (usually to feed a list), we try to fetch only those that are going to be in view so say first 20 documents. Once we reach max scroll extent we fetch the next 20.

  2. For your reload problem, try to do your fetch in say an initState function. Place it somewhere so that it will only run when it needs to. I don’t know your app structure but let’s say in my app. I had placed all initial retrieval of essential data that generally doesn’t change in my initial login logic instead of doing so every time we route to a page that needs the data

  3. Additionally, Google also has an official guide to things like Cursors. Check it out and see if other solutions can be more appropriate.

VLXU
  • 719
  • 5
  • 11
  • Hi thanks, i will have a look at the suggestions you made. My reload function works fine as i have place the above method in a init state its just that the init state runs every time that link is clicked in the nav bar – iKreateCode Jul 03 '20 at 14:47
  • Oh is this a flutter web project? – VLXU Jul 03 '20 at 14:48
  • No this is a flutter app project. I am new to flutter – iKreateCode Jul 03 '20 at 14:49
  • ‘initState’ shouldn’t run again even if ‘setState’. However, I’m guessing you mean that you had popped the route, pushed another and pushed back the one with this load function. In which case, you can try checking if your lists are still filled. If so, then no need to run load. Unless your app backend is very high paced and high traffic and expect split second changes, there is really no point to loading the data again and again every time the page comes back up. – VLXU Jul 03 '20 at 14:53
  • Okay i have managed to fix the init state. How would i listen out for newly added user to the firestore so if new users are added the init state will run then. – iKreateCode Jul 03 '20 at 15:09
  • I’ve not tried doing that but try exploring the documentation for stream.addlistener, that should allow you to listen to changes in a certain collection or document. – VLXU Jul 03 '20 at 15:16