Firebase调用setData时无法将更新数据保存至Firestore问题
问题根因
问题出在setData(_:merge:)的merge行为上:开启merge: true时,Firestore会对Map类型的字段做深度合并,不会自动删除新传入数据中不存在的旧键。
举个实际场景:原数据库里ingredientItem字段存的是["1块": "鸡胸肉", "1勺": "盐"],你删除盐之后传入的新ingredientList是["1块": "鸡胸肉"],merge逻辑只会更新新旧字典共有的键、追加新字典里新增的键,新字典里缺失的旧键(即被删除的"1勺": "盐")会完整保留在原字段里,最终表现就是删除操作不生效。
新增食材时因为是往字典里追加键值,merge逻辑只会新增内容不会暴露问题,所以你会观察到只有删除场景失效。你之前用updateData能正常运行,是因为updateData对传入的顶层字段做整体替换,不会触发嵌套深度合并,刚好符合你要整体覆盖ingredientItem字段的需求。
修复方法
选最简便的方案即可:
- 直接替换成你之前验证可用的
updateData方法,把原来的setData调用改成下面的代码:
FirebaseManager.shared.firestore .collection("users") .document(uid) .collection("userRecipes") .document(document.documentID) .updateData(["ingredientItem" : ingredientList]) { error in if let error = error { print("食材更新失败: \(error.localizedDescription)") } else { print("Updated Recipe") } }
- 如果你坚持要用
setData,就需要手动比对新旧字典的键差集,给所有被删除的键传入FieldValue.delete()标记删除,但这个方案冗余度高,完全没必要。
额外隐患提示
你当前在View内部直接初始化@ObservedObject var rm = RecipeLogic()的写法有问题,View重绘时会反复重新创建RecipeLogic实例,很容易引发后续状态错乱。如果是iOS14及以上版本,把这里改成@StateObject var rm = RecipeLogic()即可;如果兼容更低版本,建议在父视图初始化rm实例后再传入当前View。
内容的提问来源于stack exchange,提问作者Swink
相关产品推荐
相关产品推荐

