fluttergoogle-cloud-firestore

How do I pull an array from a Firestore document and convert it into a list of objects in flutter?


In my document, I have an array of notes. Each note has the writer, the note text, etc. I wrote the notes using a class called Note. I would like to pull just the notes from the document and convert them into a List of Notes.

Here is the data structure for the Note:

enter image description here

Here is the Note class, with its converter .fromFirestore:

class Note {

  String? filingId;
  final String name;
  final String note; 
  final String writerId;
  Timestamp? noteDate;
  
  Note ({
    required this.filingId,
    required this.name,
    required this.writerId,
    required this.note,
    required this.noteDate,
    });

  Map<String, dynamic> toFirestore() {
    return {
      'name': name,
      'writerId': writerId,
      'note': note,
      'noteDate': noteDate
    };
  }

  factory Note.fromFirestore(
    DocumentSnapshot<Map<String, dynamic>> snapshot,
    SnapshotOptions? options,) {
      final data = snapshot.data();
      return Note(
        noteDate: data?['noteDate'], 
        name: data?['name'],
        writerId: data?['writerId'], 
        note: data?['note'], 
        filingId: snapshot.id);
    }

}

And here is the FilingData class, which includes the notes as an array. It also has a converter .fromFiretore.

class FilingData {

  // This is the data for an entry in the timeline.
  Timestamp? createDate;
  String? filingId;
  final String jurisdiction; 
  final String filingName;
  String? frequency;
  Timestamp? nextDueDate;
  final String method;
  String? autoAssign;
  List<dynamic>? notes;
  Timestamp? updateDate;
  
  FilingData ({
    required this.createDate,
    filingId,
    required this.jurisdiction,
    required this.filingName,
    required this.frequency,
    required this.nextDueDate,
    required this.method,
    required this.autoAssign,
    notes,
    required this.updateDate,
    });    

factory FilingData.fromFirestore(
        DocumentSnapshot<Map<String, dynamic>> snapshot,
        SnapshotOptions? options,) {
          final data = snapshot.data();
          return FilingData(
            filingId: snapshot.id,
            createDate: data?['createDate'], 
            jurisdiction: data?['jurisdiction'],
            filingName: data?['filingName'], 
            frequency: data?['frequency'],
            nextDueDate: data?['nextDueDate'], 
            method: data?['method'],
            autoAssign: data?['autoAssign'],
            updateDate: data?['updateDate'],
            notes: data?['notes'] is Iterable ? List.from(data?['notes']) : null);
        }

Here is my current code to get the notes. But it does not work. First, I try to get the entire FilingData object. Then I try to pull the notes using dot-notation. Debugging shows that notesList (where I try to pull the notes using dot-notation) is null. So I'm guessing my method using dot-notation does not work. How should I do it instead? And do I have to get the full FilingData (which includes the notes array) or can I just pull the notes array?

Future<List<Note>> getAllNotes(String filingId) async {
    var ref =  _db.collection('filings').doc(filingId).withConverter(
      fromFirestore: FilingData.fromFirestore, 
      toFirestore: (FilingData, _) => FilingData.toFirestore(),
    );

    final docSnap = await ref.get();
    var notesList = docSnap.data()?.notes;
    List<Note> allNotes = [];
    // for (int i = 0; i < notesList!.length; i++) {
    //   Note thisNote = Note(name: notesList[i].name, appUserId: notesList[i].appUserId, note: notesList[i].note, noteDate: notesList[i].noteDate);
    //   allNotes.add(thisNote);
    // }
    return allNotes;
}

Solution

  • So after working on it further, I was able to do it. But it's not very elegant. First, I noticed that the FilingData class did not require the notes array. So I made that required. The following code now works:

    FilingData ({
            required this.createDate,
            filingId,
            required this.jurisdiction,
            required this.filingName,
            required this.frequency,
            required this.nextDueDate,
            required this.method,
            required this.autoAssign,
            required this.notes,
            required this.updateDate,
            });  
        
        
        
          Future<List<Note>> getAllNotes(String filingId) async {
            var ref =  _db.collection('filings').doc(filingId).withConverter(
              fromFirestore: FilingData.fromFirestore, 
              toFirestore: (FilingData, _) => FilingData.toFirestore(),
            );
        
            final docSnap = await ref.get();
            List<Note> allNotes = [];
            // Check to see if there are any notes...
            if (docSnap.data()?.notes != null) {
            List? notesList = docSnap.data()?.notes!.toList();    
            for (int i = 0; i < notesList!.length; i++) {
              
              Note thisNote = Note(
                filingId: filingId, 
                name: notesList[i]["name"], 
                writerId: notesList[i]["writerId"], 
                note: notesList[i]["note"], 
                noteDate: notesList[i]["noteDate"]);
        
              allNotes.add(thisNote);
            }
            }
            return allNotes;
        }