I’m developing an app for my school project and I stuck in an issue and I’m not able to handle it. I’m trying to get midTerm
, finalTerm
and lectureGradeId
values from my Firebase Cloud Firestore. Except that values, I’m able to get every value from Firestore.
To make it clear, I’m putting my codes and my Firestore structure below:
Students.swift
import Foundation
import FirebaseFirestore
struct Grades: Codable, Hashable {
var lectureGradeId: String
var midTerm: String
var endTerm: String
}
struct Students: Identifiable, Codable {
var id: String
var email: String
var studentName: String
var studentSurname: String
var studentTerm: String
var studentBirthday: String
var studentClass: Int
var studentDept: String
var studentFaculty: String
var studentIsActive: Bool
var studentIsGraduated: Bool
var studentLectures: [String]?
var studentGrades: [Grades]?
}
StudentsViewModel.swift
import Foundation
import Firebase
class StudentsViewModel: ObservableObject {
@Published var students = [Students]()
private var db = Firestore.firestore()
func fetchData() {
db.collection("Students").whereField("id", isEqualTo: "20704029").addSnapshotListener { querySnapshot, error in
guard let documents = querySnapshot?.documents else {
print("No documents")
return
}
self.students = documents.map { (queryDocumentSnapshot) -> Students in
let data = queryDocumentSnapshot.data()
let id = data["id"] as? String ?? ""
let email = data["email"] as? String ?? ""
let studentName = data["studentName"] as? String ?? ""
let studentSurname = data["studentSurname"] as? String ?? ""
let studentTerm = data["studentTerm"] as? String ?? ""
let studentBirthday = data["studentBirthday"] as? String ?? ""
let studentClass = data["studentClass"] as? Int ?? 0
let studentDept = data["studentDept"] as? String ?? ""
let studentFaculty = data["studentFaculty"] as? String ?? ""
let studentIsActive = data["studentIsActive"] as? Bool ?? true
let studentIsGraduated = data["studentIsGraduated"] as? Bool ?? false
let studentLectures = data["studentLectures"] as? Array ?? [""]
let student = Students(id: id, email: email, studentName: studentName, studentSurname: studentSurname, studentTerm: studentTerm, studentBirthday: studentBirthday, studentClass: studentClass, studentDept: studentDept, studentFaculty: studentFaculty, studentIsActive: studentIsActive, studentIsGraduated: studentIsGraduated, studentLectures: studentLectures)
//print(student)
return student
}
}
}
}
GradesPage.swift
import SwiftUI
struct GradesPage: View {
@ObservedObject private var viewModel = StudentsViewModel()
var body: some View {
NavigationView {
List(viewModel.students) { student in
VStack(alignment: .leading) {
Text("Student Name: ") + Text(" ") + Text(student.studentName) + Text(" ") + Text(student.studentSurname)
//I want to add the grades to see in here but don't know how to handle it
}
}
}.onAppear {
self.viewModel.fetchData()
}
}
}
Solutions that I tried:
Firestore Official Documentation
Thanks in advance, all helps are welcome!
2
Answers
After making many researchs, I finally solved my problem. First, I tried every code in the answer of @workingdog support Ukraine. But I failed at the second code snippet, normally
getDocument
method is using for a single document but I'm using many documents in my code. So, I changed my code like this:After the changes, my app started to work as I desired and here's a screenshot about it:
Now my problem is solved.
Note, you should be using
@StateObject private var viewModel = StudentsViewModel()
.Also note, there is no
finalTerm
in your codeand
NavigationView
is deprecated, useNavigationStack
To display
studentGrades
in yourGradesPage
View,simply use a
ForEach
, such as:Note, you could try mapping the results of the firebase query directly into
your codable
Students
struct, see for example:https://firebase.google.com/docs/firestore/solutions/swift-codable-data-mapping and https://firebase.google.com/docs/firestore/query-data/get-data
For example, from: https://firebase.google.com/docs/firestore/solutions/swift-codable-data-mapping