如何使用紧凑地图功能从 Firebase 的 Cloud Firestore 检索数据并对其建模?我试过了,但我的代码不起作用

How does one retrieve and model data from Firebase's Cloud Firestore using the compact map function? I tried and my code isn't working

我正在为正在制作的应用程序中的一些日志编写快照查询侦听器代码。我将数据建模为 Codable 协议,但这没有用。所以我尝试手动将键值映射到数据模型。这是模型:

// MARK: - Log Structure

struct Log : Codable {

// MARK: Properties

var date : Date

var leftUO  : Bool
var leftUI  : Bool
var leftLI  : Bool
var leftLO  : Bool

var rightUO : Bool
var rightUI : Bool
var rightLI : Bool
var rightLO : Bool

这是我尝试制作 Codable 协议的地方。

enum CodingKeys : String, CodingKey {
    
    case date   = "DATE"
    
    case leftUO = "LUO"
    case leftUI = "LUI"
    case leftLI = "LLI"
    case leftLO = "LLO"
    
    case rightUO = "RUO"
    case rightUI = "RUI"
    case rightLI = "RLI"
    case rightLO = "RLO"
    
}

func dateString() -> String {
    
    let dateformatter = DateFormatter()
    dateformatter.dateStyle = .short
    let dateString = dateformatter.string(from: date)
    
    return dateString
}

func setLogImage() -> Image {
    
    // TODO - Make icons and set image based on log
    
    let image = Image("breastIcon")
    return image
}


}

这是我用来从 Firestore 中提取数据的 ViewModel:

class Logs : ObservableObject {


// MARK: Properties
@Published var  logs =  [Log]()

// MARK: Firestore setting and retrieving Data


func createLog(uid: String, path : String,  log : Log) {
    
    let storage = Firestore.firestore()
    storage.collection(path + uid).addDocument(data: [Constants.FirebaseConstants.DATE                      : log.date,
                                                                Constants.FirebaseConstants.LEFTLOWERINNER  : log.leftLI,
                                                                Constants.FirebaseConstants.LEFTLOWEROUTER  : log.leftLO,
                                                                Constants.FirebaseConstants.LEFTUPPEROUTER  : log.leftUO,
                                                                Constants.FirebaseConstants.LEFTUPPERINNER  : log.leftUI,
                                                                Constants.FirebaseConstants.RIGHTUPPEROUTER : log.rightUO,
                                                                Constants.FirebaseConstants.RIGHTUPPERINNER : log.rightUI,
                                                                Constants.FirebaseConstants.RIGHTLOWERINNER : log.rightLI,
                                                                Constants.FirebaseConstants.RIGHTLOWEROUTER : log.rightLO
    ])
    
    
}

这是我添加querySnapshotListner的ViewModel的具体方法。

func retrieveLogs(uid: String) {
    


    let storage = Firestore.firestore()
    
    storage.collection(Constants.FirebaseConstants.LOGSCOLLECTIONS + uid).addSnapshotListener { (querySnapshot, error) in
        
        guard let documents = querySnapshot?.documents else {
            
            print(error?.localizedDescription ?? "Unable to retrieve documents.")
            return
        }
        
        self.logs = documents.compactMap({ (queryDocumentSnapshot) -> Log? in
            
            let data = queryDocumentSnapshot.data()
            
            let date    = data[Constants.FirebaseConstants.DATE]            as? Date ?? Date()
            let leftUO  = data[Constants.FirebaseConstants.LEFTUPPEROUTER]  as? Bool ?? false
            let leftUI  = data[Constants.FirebaseConstants.LEFTUPPERINNER]  as? Bool ?? false
            let leftLI  = data[Constants.FirebaseConstants.LEFTLOWERINNER]  as? Bool ?? false
            let leftLO  = data[Constants.FirebaseConstants.LEFTLOWEROUTER]  as? Bool ?? false
            
            let rightUO  = data[Constants.FirebaseConstants.RIGHTUPPEROUTER] as? Bool ?? false
            let rightUI  = data[Constants.FirebaseConstants.RIGHTUPPERINNER] as? Bool ?? false
            let rightLI  = data[Constants.FirebaseConstants.RIGHTLOWERINNER] as? Bool ?? false
            let rightLO  = data[Constants.FirebaseConstants.RIGHTLOWEROUTER] as? Bool ?? false
            
            return Log(date: date, leftUO: leftUO, leftUI: leftUI, leftLI: leftLI, leftLO: leftLO, rightUO: rightUO, rightUI: rightUI, rightLI: rightLI, rightLO: rightLO)
            
            
        })
        
    }
    print(self.logs.count)
    

}


}

我这样调用 UserInfo ViewModel 中 Logs 结构的 retrieveLogs(:_) 方法:

class UserInfo : ObservableObject {


//MARK: - Properties

@Published var user                : FBUser      = .init(uid: "", name : "", email : "")
@Published var isUserAuthenticated : FBAuthState = .undefined
@Published var userLogs            : [Log]       = []


//MARK: -  FirebaseIDToken Listener Method

func configureFirebaseStateDidChange() {
    
    _ = Auth.auth().addIDTokenDidChangeListener { [self] (_ , user) in
        
        guard user != nil else {
            
            self.isUserAuthenticated = .signedOut
            return
        }
        
        self.isUserAuthenticated = .signedIn
        
        self.user.email          = user?.email          ?? ""
        self.user.name           = user?.displayName    ?? ""
        self.user.uid            = user?.uid            ?? ""
        
        

    }
    
    guard user.uid != "" else {
        
        // UID is not retrieved
        return
    }
    
    retrieveUserLogs()
}



func retrieveUserLogs() {
    
    let logs = Logs()
    
    logs.retrieveLogs(uid: user.uid)
}



}

当在控制台上打印时,它说它的值为 0。我尝试以多种方式编辑我的代码,但都无济于事。在此先感谢您的帮助,非常感谢!!

编辑:我不断收到的错误是日志不断返回值为 0,而我期待的是一个日志数组。这是我的 Cloud Firestore 数据库的屏幕截图:

/LOGS/USERS/UID

/USERS/UID

大多数 Firebase 调用都是异步的(判断调用是异步的一个简单方法是它有一个完成块/回调)。

在您的示例中,您设置了一个将被异步调用的快照侦听器。

打印语句在快照侦听器之外,因此它会在您设置侦听器后立即执行。这是在快照侦听器收到任何数据之前,因此结果将始终为零。

将打印语句移到快照侦听器中,如下所示:

storage.collection(...).addSnapshotListener { (querySnapshot, error) in
  // ... code to map documents goes here

  self.logs = documents.compactMap(...)

  // at this time, self.logs will contain the collection of mapped documents (1)
  print(self.logs.count)
}

注意 (1) - 假设集合非空,并且可以映射文档(即使用所有正确的字段名称)。

再次强调,我强烈建议使用 Firebase 的 Codable 支持。如果您 post Firestore 数据浏览器中数据模型的屏幕截图,我可以尝试为您绘制映射代码。