0
votes

I'm developing a flutter app and using firestore as backend: my DB structure is:

  • User (Collection)
    • userid (User property)
    • Books (SubCollection)
      • booksList (array of Objects(or map as firestore calls them))

The function to retrieve each book from booksList array is:

Future<List<Book>> bookshelf(String userId) async {
  return await FirebaseFirestore.instance
      .collection('Users')
      .where('userId', isEqualTo: userId)
      .get()
      .then((querySnapshot) => querySnapshot.docs.map((doc) => doc.reference
          .collection('Books')
          .get()
          .then((querySnapshot) => querySnapshot.docs.forEach((doc) {
                var books = doc.data()['bookList'];
                return books
                    .map<Book>((elem) => Book(title: elem['title']));
              }))).toList());

My problem is that I'm not able to return Future<List<Book>>;
I've tried to create an array and add elements to it at line 12 (where I'm actually getting the books correctly) but it didn't work since the return statement wasn't waiting for the query to complete.
Basically I'm not able to transform the object I get into a Future<List> as I need for the function. Right now I'm getting a "MappedListIterable<QueryDocumentSnapshot, Future>".
Thanks.

1
Wat are u getting now?Peter Haddad
@salmansamadi: that's on java and I'm not really sure about how to make it in dart since the methods are completely different.Antonel Gabor
@PeterHaddad: I get a "MappedListIterable<QueryDocumentSnapshot, Future<void>>"Antonel Gabor

1 Answers

0
votes

The error is caused by the forEach method inside the most nested Promise callback, because the forEach method always returns void, however a Book is expected. There will also be an error caused by the nested lists, which can be resolved by flattening the nested lists using the expand method. I have modified your code sample to remove the forEach method and reduce the Promise callback nesting:

Future<List<Book>> bookshelf(String userId) async {
  return await FirebaseFirestore.instance
      .collection('Users')
      .where('userId', isEqualTo: userId)
      .get()
      // Maps each user query snapshot to a list of book query snapshots.
      .then(
        (snapshot) => Future.wait(
          snapshot.docs.map((doc) => doc.reference.collection('Books').get()),
        ),
      )
      // Maps each list of book query snapshots to a list of book document snapshots.
      .then(
        (snapshots) => snapshots.expand((snapshot) => snapshot.docs),
      )
      // Maps each list of book document snapshots to a list of raw books.
      .then(
        (docs) => docs.expand((doc) => doc.data()['bookList'] as List),
      )
      // Maps each list of raw books to a list of books.
      .then(
        (books) => books.map((book) => Book(title: book['title'])).toList(),
      );
}