1
votes

I am learning flutter mostly by reading posts here and watching YouTube videos but it seems I have reached the point where the videos don't cover what I need so I am coming here to get help.

I am trying to understand Streams, Firebase, and mapping.

I need to create a StreamProvider using Riverpod. This is the code I am using to create the StreamProvider:

final trxnStreamProvider = StreamProvider.autoDispose<List<Trxns>>((ref) {
  final stream = firestoreService.getAgencyTrxns();
  return stream.map((snapshot) => snapshot.docs.map((doc) =>
      Trxns.fromFirestore(doc.data)).toList());
});

I get the stream from Firebase in this code:

  Stream<QuerySnapshot> getAgencyTrxns() async* {
    yield* FirebaseFirestore.instance
        .collection('agency').doc(globals.agencyId)
        .collection('trxns')
        .where('trxnStatus', isNotEqualTo: 'Closed')
        .snapshots();
  }

So, I get a QuerySnapshot from Firebase according to the snippet above. This works well.

Then, this QuerySnapshot gets returned to the "stream" variable in the first code snippet where I am creating the StreamProvider.

The QuerySnapshot variable, "stream", is then mapped to <List> and returned to trxnStreamProvider by this code.

return stream.map((snapshot) => snapshot.docs.map((doc) =>
          Trxns.fromFirestore(doc.data)).toList());

I am getting an error at "doc.data" stating: The argument type 'Object? Function()' can't be assigned to the parameter type 'Map<String, dynamic>'.

I am trying to understand what exactly what this line of code is doing and I need your help.

return stream.map((snapshot) => snapshot.docs.map((doc) =>
          Trxns.fromFirestore(doc.data)).toList());

Let me tell you what I think it is doing:

  1. The variable stream has a method called "map" and is called to map the QuerySnapshot to a list. I'm not sure where "snapshot" comes from but I think it is the QuerySnapshot returned from Firebase with this call, firestoreService.getAgencyTrxns().

  2. The QuerySnapshot consists of documents contained in the Firebase collection, "trxns". This explains snapshot.docs and now we want to map each of these docs using the snapshot.docs.map() method to a list. I am passing each individual doc to be mapped using this code: snapshot.docs.map(doc).

  3. I am using the method, Trxns.fromFirestore(doc.data)).toList(), to map the elements contained in the document to a list. The type of list that will be returned will be Map<String, dynamic> (I think).

Here is the mapping code:

Trxns.fromFirestore(Map<String, dynamic> firestore)
      : trxnId = firestore['trxnId'],
        agentId = firestore['agentId'],
        agencyId = firestore['agencyId'];

In the returned map would look something like this:

trxnId: somevalue, agentId: somevalue, agencyId: somevalue;

Is this correct?

These are all members of the Trxns class so it now has the form of a <List>. Is this correct?

So, "doc.data" is simply a snapshot of one of the documents in the QuerySnapshot, correct?

Why am I getting the error on "doc.data"?

enter image description here

1

1 Answers

1
votes

Change it to this, and cast it as a Map:

return stream.map((snapshot) => snapshot.docs.map((doc) =>
Trxns.fromFirestore(doc.data() as Map<String, dynamic>)).toList());

To access the actual Map inside your doc, you need to use data() to get all the keys, or you can use .get('name') for example to get the specific key called name in your document.

So, "doc.data" is simply a snapshot of one of the documents in the QuerySnapshot, correct?

Correct, QuerySnapshot is a list of DocumentSnapshots, and they are held together in the object named docs. You can perform list operations on docs such as length, and as you did docs.map.

The only thing you missed was invoking the data function. When you type doc.data, here think of data as a reference to a function which extracts the {key:value} pairs from your document, it contains all the logic behind the scenes written by Firebase, but if you stop there without using the (), this function is not called.

So just fixing the type by using doc.data(), should solve your issue.