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

FireStore批量更新:Swift中同步用户收藏食谱属性的高效实现

高效同步更新用户收藏食谱的Swift实现方案

1. 提前构建反向映射关系

在Firestore中新增recipeFavorites集合,每个文档ID对应食谱ID,文档内用userIds数组存储所有收藏该食谱的用户ID:

  • 用户收藏食谱时,除了往自身fav_recipes添加条目,还要用arrayUnion往recipeFavorites/{recipeId}的userIds数组追加当前用户ID(自动去重)。
  • 用户取消收藏时,用arrayRemove从userIds数组移除自身ID。

Swift代码示例(收藏操作):

func addRecipeToFavorites(recipeId: String, userId: String, recipeData: [String: Any]) {
    let db = Firestore.firestore()
    // 更新用户个人收藏列表
    db.collection("users").document(userId).collection("fav_recipes").document(recipeId).setData(recipeData)
    // 更新反向映射集合
    db.collection("recipeFavorites").document(recipeId).updateData([
        "userIds": FieldValue.arrayUnion([userId])
    ])
}

2. 修改食谱时批量更新收藏条目

当食谱属性(如名称)修改后,先获取该食谱的最新数据,再通过recipeFavorites拿到所有收藏用户ID,用Firestore批量写操作同步更新:

注意:Firestore单批写操作最多支持500个任务,用户数量超过500时需拆分批次处理。

Swift代码示例:

func updateFavoritesForModifiedRecipe(recipeId: String, updatedData: [String: Any]) {
    let db = Firestore.firestore()
    // 1. 获取所有收藏该食谱的用户ID
    db.collection("recipeFavorites").document(recipeId).getDocument { snapshot, error in
        guard let snapshot = snapshot, let userIds = snapshot["userIds"] as? [String], !userIds.isEmpty else {
            return
        }
        
        // 2. 拆分用户ID为500个一组的批次
        let batches = stride(from: 0, to: userIds.count, by: 500).map {
            userIds[$0..<min($0+500, userIds.count)]
        }
        
        // 3. 逐批次执行批量更新
        batches.forEach { batchUserIds in
            let batch = db.batch()
            batchUserIds.forEach { userId in
                let favRecipeRef = db.collection("users").document(userId).collection("fav_recipes").document(recipeId)
                batch.setData(updatedData, forDocument: favRecipeRef, merge: true)
            }
            batch.commit { error in
                if let error = error {
                    print("批次更新失败: \(error.localizedDescription)")
                }
            }
        }
    }
}

3. 简化方案:避免重复存储,直接引用原食谱

如果不想维护反向映射集合,可调整数据结构:用户fav_recipes只存储食谱ID,展示收藏列表时通过ID实时从原食谱集合拉取最新数据。这种方式无需同步操作,但展示时需额外查询。

Swift代码示例(拉取收藏列表):

func fetchFavoriteRecipes(userId: String, completion: @escaping ([Recipe]) -> Void) {
    let db = Firestore.firestore()
    // 先获取用户收藏的食谱ID列表
    db.collection("users").document(userId).collection("fav_recipes").getDocuments { snapshot, error in
        guard let docs = snapshot?.documents else {
            completion([])
            return
        }
        let recipeIds = docs.compactMap { $0.documentID }
        guard !recipeIds.isEmpty else {
            completion([])
            return
        }
        // 批量拉取原食谱的最新数据
        db.collection("recipes").whereField("id", in: recipeIds).getDocuments { recipeSnapshot, error in
            let recipes = recipeSnapshot?.documents.compactMap { Recipe(dictionary: $0.data()) } ?? []
            completion(recipes)
        }
    }
}

方案选择建议

  • 若需低延迟实时展示收藏内容,选反向映射+批量更新方案,需维护额外集合。
  • 若追求简化数据结构、降低维护成本,选存储ID+实时拉取方案,牺牲少量查询性能。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.18 10:33:33