You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Swift中从Firestore获取含Map的数组值问题求助

问题:无法从Firebase Firestore获取midTerm、finalTerm和lectureGradeId字段值

我正在为学校项目开发一款App,目前遇到了无法解决的问题:尝试从Firebase Cloud Firestore中获取midTerm、finalTerm和lectureGradeId的值,但除了这些值之外,能成功获取Firestore中的所有其他数据。


相关代码

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()
    }
}
}

Firestore结构

Firestore Structure


已尝试的解决方案

  • 参考Firestore Codable相关指南
  • 查阅Firestore官方文档

解决方案

1. 修正字段名不匹配问题

Firestore中的成绩字段是finalTerm,但你定义的Grades结构体里写的是endTerm,字段名不匹配会导致解析失败。修改结构体:

struct Grades: Codable, Hashable {
    var lectureGradeId: String
    var midTerm: String
    var finalTerm: String // 改为和Firestore一致的字段名
}

2. 改用Codable自动解析(替代手动赋值)

手动解析容易遗漏字段(比如你没处理studentGrades),用Firestore自带的Codable支持更可靠,修改fetchData方法:

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.compactMap { document in
            do {
                // 直接将文档解码为Students对象
                let student = try document.data(as: Students.self)
                return student
            } catch {
                print("解码失败:\(error)")
                return nil
            }
        }
    }
}

3. 在页面中展示成绩数据

现在student.studentGrades已能正确获取,修改GradesPage的视图代码:

VStack(alignment: .leading) {
    Text("Student Name: ") + Text(" ") + Text(student.studentName) + Text(" ") + Text(student.studentSurname)
    
    // 遍历展示成绩
    if let grades = student.studentGrades {
        ForEach(grades, id: \.lectureGradeId) { grade in
            VStack(alignment: .leading, spacing: 4) {
                Text("课程ID:\(grade.lectureGradeId)")
                Text("期中成绩:\(grade.midTerm)")
                Text("期末成绩:\(grade.finalTerm)")
            }
            .padding(.vertical, 8)
            .border(.gray, width: 0.5)
            .padding(.vertical, 4)
        }
    }
}

内容的提问来源于stack exchange,提问作者caneraltuner

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.23 03:01:10