【问题标题】:Duplicated document in collection when added to Firestore添加到 Firestore 时集合中的重复文档
【发布时间】:2022-11-14 17:13:35
【问题描述】:

有一个handlerDoneTapped() 函数,当单击Done 按钮时应用该函数,它将字段中的数据(包括图像和path)保存到Firestore 中。

    func handleDoneTapped() {
        self.viewModel.handleDoneTapped()
        self.uploadImage()      // For Storage and path to it         
        self.dismiss()
    }

handleDoneTapped() 函数内部,还有另一个uploadImage() 函数将图像上传到Storage 并将path 保存到pic 参数。

    @ObservedObject var viewModel = NewItemView()

    func uploadImage() {
        let storage = Storage.storage().reference()
        let picData: Data = pickedImages[0].jpegData(compressionQuality: 0.5)!
        let path = "itemImages/\(UUID().uuidString).jpg"
        let ref = storage.child(path)
        let metadata = StorageMetadata()
        metadata.contentType = "image/jpg"
        _ = ref.putData(picData, metadata: metadata, completion: { (storageMetaData, error) in
            if error != nil {
                print(error?.localizedDescription as Any)
                return
            } else {

                self.viewModel.singleitem.pic = path      // I specify the path to the pic parameter [singleitem - also from NewItemView()]
                self.viewModel.updateOrAddItem()        // I make changes through the function from NewItemView()
                
            }
        })
        }

@ObservedObject var viewModel = NewItemView() - 让我们参考 Firestore 参数来保存数据。

  class NewItemView: ObservableObject {

  @Published var singleitem: SingleItem

    init(singleitem: SingleItem = SingleItem(title: "", author: "", description: "", pic: "")) {
    self.singleitem = singleitem
    
      self.$singleitem
      .dropFirst()
      .sink { [weak self] singleitem in
        self?.modified = true
      }
      .store(in: &self.cancellables)
  }

  private var db = Firestore.firestore()
    
  private func addItem(_ singleitem: SingleItem) {
    do {
        var addedItem = singleitem
        addedItem.userId = Auth.auth().currentUser?.uid
        _ = try db.collection("items").addDocument(from: addedItem)
    }
    catch {
      print(error)
    }
  }

  private func updateItem(_ singleitem: SingleItem) {
    if let documentID = singleitem.id {
      do {
          try db.collection("items").document(documentID).setData(from: singleitem)
      }
      catch {
        print(error)
      }
    }
  }
  
  public func updateOrAddItem() {          // This func I call inside uploadImage() to update path for pic parameter
                                           // (bc without that pic: "" -is empty inside Firestore)
    
      if singleitem.id != nil {
      self.updateItem(self.singleitem)
    }
    else {
      addItem(singleitem)
    }
  }

 func handleDoneTapped() {         // This func I call when I tapped Done button to add or update item
    self.updateOrAddItem()
  }

最后 SingleItem 结构与所有 vars:

struct SingleItem: Identifiable, FirestoreProtocol {
    @DocumentID var id : String?
    @ServerTimestamp var createdTime: Timestamp?
    var title : String
    var author : String
    var description : String
    var userId : String?
    var pic : String
}
  
  enum CodingKeys: String, CodingKey {
    case id
    case title
    case author
    case description = ""
    case pic
  }

所以,我知道我调用了两次self.viewModel.updateOrAddItem() 函数,但是如果我不在uploadImage() 中使用这个函数,那么文档会在没有pic 参数的情况下保存,其中包含path 到图像中贮存。 但是当我在uplaodImage() 中使用这个函数时,两个相同的文档被保存到Firestore 中,不同之处在于其中一个包含pathpic 字段中的图像。

总的来说,我有点困惑,我尝试使用这些函数更改输入数据的参数,以过滤掉不包含必要信息的重复文档,但一切都导致文档保存时没有一个pic字段(path里面是空的),或者两个,其中一个需要,另一个不需要。

也许有人会看到我在哪里犯了错误。此外,我只提供了与问题相关的必要代码,部分代码以及可能缺少括号。

【问题讨论】:

  • 如果视图被重绘,这个`@ObservedObject var viewModel = NewItemView()` 有可能创建新的视图模型实例。视图模型应该从超级视图注入或来自环境。您的uploadImage 代码也属于您的视图模型或模型。
  • 你有没有试过使用@StateObject var viewModel = NewItemView()
  • @workingdogsupportUkraine 是的,没有任何变化。
  • 您能否添加您的 Firebase 控制台的屏幕截图,显示两个不正确的文档。我假设如果您有两个,那么它们具有不同的 ID,对吗?

标签: ios xcode swiftui firebase-storage


【解决方案1】:

根据您提供的信息,听起来您上传了两次对象。我可以告诉您,您的代码会出现一些异步问题,所以我假设这就是问题所在,如果这不起作用,请提供更多信息。

在您的addItem 函数中,您永远不会将更新保存到singleitem

private func addItem(_ singleitem: SingleItem) {
    do {
        var addedItem = singleitem
        addedItem.userId = Auth.auth().currentUser?.uid

        // Since you are adding the document to Firebase, you need to update
        //     your local object. This will give it the generated ID from Firebase
        _ = try db.collection("items").addDocument(from: addedItem) { err in
            if let err = err {
                print("Error adding document: (err)")
            } else {
                print("Document added with ID: (ref!.documentID)")
                self.singleItem.id = ref!.documentID
            }
        }
    }
    catch {
      print(error)
    }
  }

我猜如果你要调试你的 updateOrAddItem 函数,updateItem 永远不会被调用,因为 ID 永远不会保存到 singleitem

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2020-03-04
    • 2020-01-05
    • 2019-06-04
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多