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

Firestore多子集合获取保养记录 添加新记录后出现重复问题

解决Firestore获取保养记录时的重复数据问题

问题根源

  • 使用addSnapshotListener时,每次数据更新(包括新增、修改记录)都会触发回调,原代码每次触发都直接将当前车辆的所有保养记录追加到expenseItems数组中,旧数据未被清理,导致重复累积。
  • 循环处理多辆车时,每辆车的监听器独立触发,每次触发都往同一个expenseItems里追加数据,进一步加剧重复问题。
  • 遇到无ID的车辆时直接return,会导致后续车辆的记录无法被获取。

修复方案

  1. 新增字典存储单辆车的保养记录,避免不同车辆的记录混乱。
  2. 每次监听器触发时,更新对应车辆的记录到字典中,再将字典中所有记录扁平合并为完整列表,替换expenseItems而非追加。
  3. 将无ID车辆的return改为continue,确保后续车辆正常处理。

修改后的代码

import Foundation
import FirebaseFirestore
import FirebaseFirestoreSwift

class ExpensesManager: ObservableObject {
    // 用字典存储各车辆的保养记录,key为车辆ID
    private var vehicleExpenses: [String: [MaintenanceItem]] = [:]
    @Published private(set) var expenseItems: [MaintenanceItem] = []
    let db = Firestore.firestore()
    
    init(vehicles: [Vehicle]) {
        fetchExpenseItems(vehicles: vehicles)
        print("ExpensesManager init func succeess!")
    }
    
    func fetchExpenseItems(vehicles: [Vehicle]) {
        for vehicle in vehicles {
            guard let vehicleID = vehicle.id else {
                print("VehicleID is not found, skip this vehicle")
                continue // 改为continue,不终止后续车辆处理
            }
            
            db.collection("Vehicles").document(vehicleID).collection("MaintenanceItems")
                .addSnapshotListener { [weak self] querySnapshot, error in
                    guard let self = self else { return }
                    guard let documents = querySnapshot?.documents else {
                        print("Error fetching documents: \(String(describing: error))")
                        return
                    }
                    
                    // 解析当前车辆的保养记录
                    let newExpenses = documents.compactMap { document -> MaintenanceItem? in
                        do {
                            return try document.data(as: MaintenanceItem.self)
                        } catch {
                            print("Error decoding document into Expense: \(error)")
                            return nil
                        }
                    }
                    
                    // 更新字典中对应车辆的记录
                    self.vehicleExpenses[vehicleID] = newExpenses
                    // 扁平合并所有车辆的记录,生成完整列表
                    self.expenseItems = self.vehicleExpenses.values.flatMap { $0 }
                    
                    print("Expenses array updated, total items: \(self.expenseItems.count)")
                }
        }
    }
}

关键改动说明

  • vehicleExpenses字典:单独存储每辆车的保养记录,避免不同车辆的数据互相干扰。
  • 替换而非追加:每次监听器触发时,先更新对应车辆的记录,再重新合并生成完整的expenseItems,彻底解决重复问题。
  • continue替代return:确保即使某辆车无ID,后续车辆的记录仍能正常获取。
  • [weak self]避免循环引用:在闭包中使用弱引用,防止内存泄漏。

内容的提问来源于stack exchange,提问作者Ilia Krasnobaev

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.16 13:40:42