如何使用紧凑地图功能从 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 数据浏览器中数据模型的屏幕截图,我可以尝试为您绘制映射代码。
我正在为正在制作的应用程序中的一些日志编写快照查询侦听器代码。我将数据建模为 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 数据浏览器中数据模型的屏幕截图,我可以尝试为您绘制映射代码。