Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Firebase Cloud Firestore get array of maps in Flutter

I'm trying to build something in Flutter using Firebase Cloud Firestore as my database. I have a collection ('students') which contains a document of each student.

Within each student document there is an array which contains a map of marks for the student. See below.

Screenshot from Firebase Cloud Firestore document with an array (grades) of maps (various fields relating to the marks a student has received)

In Flutter I have the following classes:

class Student {
  final String name;
  final String subject;
  final List<Mark> marks;

  Student({this.name, this.subject, this.marks});
}

class Mark {
  final int mark;
  final String grade;
  final String markedBy;
  final String feedback;

  Mark({this.mark, this.grade, this.markedBy, this.feedback});
}

I'm retrieving the data using a Provider stream as follows:

  Stream<List<Student>> get firebaseStudents {
    return Firestore.instance.collection('students').snapshots().map(_firebaseStudentsFromSnapshot);
  }

  List<Student> _firebaseStudentsFromSnapshot(QuerySnapshot snapshot) {
    return snapshot.documents.map((doc) {
      return Student(
        name: doc.data['name'] ?? '',
        subject: doc.data['subject'] ?? '',

        //trying to figure out how to map the marks!

      );
    }).toList();
  }

If I print doc.data['grades'] I can see it is an array of maps with the data in, I'm just not sure how to then map that to a list of the class Mark.

I've looked around and seen suggestions such as using fromMap but can't seem to get it working. I've tried the below (in Mark class):

  Mark.fromMap(Map<String,dynamic> map) : 
    mark = map['mark'], 
    grade = map['grade'],
    markedBy = map['markedBy'],
    feedback = map['feedback'];

And in the database retrieve:

  marks: List<Mark>.from(doc.data['grades'].map((item) {
    return new Mark(
        mark: item['mark'],
        grade: item['grade'],
        markedBy = item['markedBy'],
        feedback = map['feedback']
       );
     })),

But to no avail. I'm sure I'm just missing a key part but I'm still fairly new to this so I'm trying to get my head around all of this.

Thanks in advance for any help or advice.

Edit

Ultimately figured something out that works but always happy to hear if there are better ways of doing this.

I presume there probably is a smarter way of doing it using a fromMap but currently the type differences are causing me a problem but will see if I can get that working as that would be a bit neater.

  List<Student> _firebaseStudentsFromSnapshot(QuerySnapshot snapshot) {
    return snapshot.documents.map((doc) {
      List<Mark> marks = [];
      List<dynamic> markMap = doc.data['grades'];
      markMap.forEach((element) {
        marks.add(new Mark(
            mark = element['mark'], 
            grade = element['grade'],
            markedBy = element['markedBy'],
            feedback = element['feedback'];
        ));
      });
      return Student(
        name: doc.data['name'] ?? '',
        subject: doc.data['subject'] ?? '',
        marks: marks,
      );
    }).toList();
  }
like image 607
ashleytwo Avatar asked Jul 19 '20 09:07

ashleytwo


1 Answers

Ended up finding a solution myself, unsure if its the best but it worked for me.

  List<Student> _firebaseStudentsFromSnapshot(QuerySnapshot snapshot) {
    return snapshot.documents.map((doc) {
      List<Mark> marks = [];
      List<dynamic> markMap = doc.data['grades'];
      markMap.forEach((element) {
        marks.add(new Mark(
            mark = element['mark'], 
            grade = element['grade'],
            markedBy = element['markedBy'],
            feedback = element['feedback'];
        ));
      });
      return Student(
        name: doc.data['name'] ?? '',
        subject: doc.data['subject'] ?? '',
        marks: marks,
      );
    }).toList();
  }
like image 193
ashleytwo Avatar answered Nov 15 '22 11:11

ashleytwo