swift - 返回并订阅 Firestore 子集合中的最新值
问题描述
我正在尝试加载或创建一个“季节”,它基本上是一个季度或一个月的时间块,作为子集合文档存储在云 Firestore 中的用户配置文件中。
我在 Season 子集合中有一个“order”字段,它随着每个新创建的季节而增加,我的查询只是找到最近的一个。
我调用这个函数(loadOrCreateCurrentSeason)来加载最近的季节,它返回一个组合未来——我的数据模型中的一个季节或一个错误,它订阅了它。只要没有错误,它就会返回它找到的季节,只要它返回的季节包含当前日期。
如果其中任何一个不正确,它将创建一个新文档并将该文档添加到 Firebase。
我遇到的问题是,在我用来返回最新季节的辅助函数中,当它加载文档并尝试将其转换为我的应用程序的季节模型(let x = try document.data(as: Season.self
)时,我的应用程序一直返回 x 为零。
我不确定这是否是我的查询错误,或者我如何设置函数以将数据作为季节返回,但我想知道是否有任何东西可能阻止应用程序转换 Firestore文档成一个季节?
初始化存储库时调用的主函数:
func loadOrCreateCurrentSeason() {
var _ = loadMostRecentSeason()
.sink(receiveCompletion: { error in
self.addSeasonToSubcollection(season: Season(lastOrder: 0))
}, receiveValue: { [weak self] season in
if season.endDate < Date() {
let oldOrder = season.order
self?.saveCurrentSeasonToPast()
self?.currentSeason = self?.createCurrentSeason(order: oldOrder)
self?.addSeasonToSubcollection(season: season)
} else {
self?.currentSeason = season
}
})
.store(in: &cancellables)
}
调用帮助函数以专门从 Firebase 加载最新季节:
func loadMostRecentSeason() -> Future<Season, ErrorLoadingSeason> {
let seasonRef = db.collection("users").document(userProfile.id!).collection("season")
return Future<Season, ErrorLoadingSeason> { promise in
seasonRef.order(by: "order", descending: true)
.limit(to: 1)
.getDocuments() { (querySnapshot, err) in
if let err = err {
print("Error getting most recent season: \(err.localizedDescription)")
promise(Result.failure(ErrorLoadingSeason.NoSeasonFound))
} else {
for document in querySnapshot!.documents {
do {
let x = try document.data(as: Season.self)
if x != nil {
promise(Result.success(x!))
} else {
promise(Result.failure(ErrorLoadingSeason.NoSeasonFound))
}
} catch {
print("An error converting the most recent season")
print(error)
promise(Result.failure(ErrorLoadingSeason.couldNotConvertData))
}
}
}
}
}
}
如果这有所不同,这是我的季节结构:
struct Season: Codable, Identifiable {
// Identifiers
@DocumentID var id: String?
var title: String?
var userId: String
var order: Int
//Completion Details
var startDate: Date
var endDate: Date
// var seasonType: SeasonType?
init(lastOrder: Int) {
let userProfile = CurrentUserProfile.shared.currentUser!
self.userId = userProfile.id!
self.startDate = Date().startOfPeriod(userProfile.seasonLength ?? .quarter)
self.endDate = Date().endOfPeriod(userProfile.seasonLength ?? .quarter)
self.order = lastOrder + 1
self.title = setTitle(userProfile: userProfile)
}
}
解决方案
看起来这个问题与我如何在 .sink 方法中接收完成有关。
以前我把它设置为:
.sink(receiveCompletion: { error in
self.addSeasonToSubcollection(season: Season(lastOrder: 0))
}, receiveValue: ...
我曾认为因为它没有撞到receiveValue:
块,所以 x 一定没有设置,但似乎我需要对错误和成功完成的失败进行不同的处理(似乎是一个非常基本的错误)。
如果成功完成,添加一个 switch 语句来中断,似乎已经解决了这个问题:
func loadOrCreateCurrentSeason() {
var _ = loadMostRecentSeason()
.sink(receiveCompletion: { completion in
switch completion {
case .finished:
break
case .failure(let error):
print(error)
self.addSeasonToSubcollection(season: Season(lastOrder: 0))
}
}, receiveValue: { [weak self] season in
if season.endDate < Date() {
let oldOrder = season.order
self?.currentSeason = self?.createCurrentSeason(order: oldOrder)
self?.addSeasonToSubcollection(season: Season(lastOrder: oldOrder))
} else {
self?.currentSeason = season
}
})
.store(in: &cancellables)
}
推荐阅读
- python - Celery 4.4.0、django 和 Flower:Celery worker 接收到已经被其他 worker 执行的任务。它未执行但已添加到已处理
- python - 当您登录时我需要一条短信“您的密码不正确”
- python - Beautifulsoup 按其类名提取 div
- python - 如何在 R 或 Python 语言中以状态空间形式估计 GARCH-M?
- javascript - 用于 slug url 的 Next.js 路由,例如 site.com/username
- ssh - 手动应答 SSH 质询响应身份验证
- sql - 尽管 Main Line 在标准中为 True,但在 NetSuite 中保存的搜索会为每个供应商账单返回多行
- sql - postgresql中group by的奇怪行为
- javascript - 搜索 objects.shortName 数组以及嵌套的对象数组
- python - 如何打印存储在列表中的对象的值