Home > Software design >  Firebase not retrieving nested collection documents in Flutter project
Firebase not retrieving nested collection documents in Flutter project

Time:04-04

I've been working on a messaging app in Flutter and have been having some trouble with retrieving collection data from Firestore. I'm trying to retrieve a list of contacts for a user. This is my db structure: Firestore stucture

I was following a slightly outdated tutorial that was using a stream transformer & mapping function to return a Stream of List like this:

final contactsStream = userRef.snapshots().transform(
    StreamTransformer<DocumentSnapshot, List<Contact>>.fromHandlers(
        handleData: (documentSnapshot, sink) => mapDocumentToContact(
            usersRef, userRef, documentSnapshot, sink)));

Mapping function:

Future<void> mapDocumentToContact(
  CollectionReference userCollectionReference,
  DocumentReference contactReference,
  DocumentSnapshot documentSnapshot,
  Sink sink) async {
List<String> contacts;

   final data = documentSnapshot.data() as DocumentSnapshot;

if (data['contacts'] == null || data['conversations'] == null) {
  await contactReference.update({'contacts': []});
  contacts = [];
} else {
  contacts = List.from(data['contacts']);
}

final contactList = <Contact>[];

final Map? conversations = data['conversations'];

for (final username in contacts) {
  final id = await getUserIdByUsername(username: username);
  final contactSnapshot = await userCollectionReference.doc(id).get();
  final Map<String, dynamic> contactSnapshotData =
      contactSnapshot.data() as Map<String, dynamic>;

  contactSnapshotData['conversationId'] = conversations![username];
  contactList.add(Contact.fromFirestore(contactSnapshot));
}
sink.add(contactList);

This method, however throws a _StreamHandlerTransformer<DocumentSnapshot<Object?>, List<Contact>>' is not a subtype of type 'StreamTransformer<DocumentSnapshot<Map<String, dynamic>>, List<Contact>>' of 'streamTransformer’ error that I can't seem to get rid of no matter what combination of examples I've found online I try, so I've tried to just implement a simpler get() for the contacts (paths are normally set during runtime but I've got it here explicitly for debugging):

   QuerySnapshot<Map<String, dynamic>> snapshot = await fireStoreDb
    .collection('/users')
    .doc('yoTl9LhxxuaiIuo8jiMZjSXR0sU2')
    .collection('contacts')
    .get();

var contactList = snapshot.docs
    .map((docSnapshot) => Contact.fromFirestore(docSnapshot))
    .toList();

Mapping function:

  factory Contact.fromFirestore(DocumentSnapshot document) {
final Map data = document.data() as Map<String, dynamic>;
return Contact(
    document.id,
    data['username'], 
    data['conversationId']);

This doesn't throw any errors but it also doesn't seem to fetch the contacts at all. I'm able to fetch the list of users using the same method, but as soon as I try a level down it doesn't return anything. I am, regrettably, at my wits' end, does anyone know what is happening here? Thanks.

CodePudding user response:

contacts is a List not a sub-collection.

You can access it as below:

DocumentSnapshot<Map<String, dynamic>> snapshot = await FirebaseFirestore
    .instance
    .collection('users')
    .doc('yoTl9LhxxuaiIuo8jiMZjSXR0sU2')
    .get();

Map<String, dynamic>? user = snapshot.data();
print(user?['contacts']); // should print list of contacts

CodePudding user response:

Looking at the screenshot of your firestore DB, contacts is not a sub-collection. But you are trying to read it as a sub collection. Contacts is either a List or Map.

  • Related