Home > Back-end >  Join two firestore collections in FLutter
Join two firestore collections in FLutter

Time:08-13

I have two collections in firestore. One of them is "users" and the otherone is "teams". Right now they are uid related with the lists "teamMembersUid" and "teamsMemberUid" as you can see in the code:

class UserModel {
  String? uid;
  String? email;
  String? firstName;
  String? secondName;
  String? userName;
  String? teamSelected;
  List<String>? teamsMemberUid;
  List<String>? notifications;


class TeamModel {
  String? uid;
  String? teamName;

  List<String>? teamMembersUid;
  List<UserModel>? teamMembers;
  List<String>? publicationsUid;
  List<String>? notifications;
  List<String>? instancesUid;

I want to create an app state that is a list of teams to which the logged in user belongs. Within each team I want a list of each user that belongs to the team with their information (teamMembers). I want that information locally and dont upload it to firestore. The function I have been trying to create is this:

Future<List<TeamModel>> getTeamsWithUsersInfo(String? userUid) async {
    List<TeamModel> retVal = [];
    try {
      //Create a list with the teams to which the user belongs from firestore
      final data = await _firestore
          .collection("teams")
          .where("teamMembersUid", arrayContains: userUid)
          .get();
      List<TeamModel> data_m =
          List.from(data.docs.map((doc) => TeamModel.fromMap(doc)));  
      //Fill teamMembers list with users information
      data_m.forEach((element) async {
        await getTeamUsersInfo(element.teamMembersUid!)
            .then((List<UserModel> users) {
          element.teamMembers = users;
          retVal.add(element);
        });
      });    
    } catch (e) {
      print(e);
    }
    return retVal;
  }

getTeamUserInfo function is this:

Future<List<UserModel>> getTeamUsersInfo(List<String> teamMembersUid) async {
    List<UserModel> retVal = [];

    teamMembersUid.forEach((element) async {
      await getUserInfo(element).then((userData) => retVal.add(userData));
    });
    return retVal;
  }

getUserInfo function is this:

Future<UserModel> getUserInfo(String uid) async {
    UserModel retVal = UserModel();
    try {
      DocumentSnapshot _docSnapshot =
          await _firestore.collection('users').doc(uid).get();
      retVal = UserModel.fromMap(_docSnapshot);
      return retVal;
    } catch (e) {
      print(e);
    }
    return retVal;
  }

In the debug mode I am able to see that getTeamUsersInfo gets the list of users of the different teams, but it happens after the getTeamWithUsersInfo output a list of teams with the teamMembers field empty, so after getTeamUsersInfo get executed the function getTeamWithUsersInfo isn't executed again.

Do you see any error or something suspicious in the code? Do you know any more effective way to do joins in firestore?

CodePudding user response:

I have a few things that can be checked / improved

  1. You are not awaiting this so the process will proceed without waiting for the result: data_m.forEach((element) async {

  2. Don't combine await and then as here: await getTeamUsersInfo(element.teamMembersUid!).then Check this SO answer.

  3. Don't use the forEach-async combo as you do. Check this SO answer.

You could try with:

await Future.forEach(data_m, (element) async {
  final users = await getTeamUsersInfo(element.teamMembersUid!);
  element.teamMembers = users;
  retVal.add(element);
}

  • Related