Firebase - 跨多个位置的原子写入不起作用

Posted

技术标签:

【中文标题】Firebase - 跨多个位置的原子写入不起作用【英文标题】:Firebase - Atomic writes Across Multiple Locations not working 【发布时间】:2017-06-07 22:39:41 【问题描述】:

如何使用此功能更新 Firebase 中的实时数据库?我设法使该功能正常工作,但仅在触发 updateChild 时为帖子编写新 ID。如何通过帖子 ID 更新当前帖子?

   var pathToPictures = [Pictures]()
   func updateAllImagesOfCurrentUserInDatabase() 

    //refrences
    let ref = FIRDatabase.database().reference()
    let uid = FIRAuth.auth()?.currentUser?.uid

    //match the user ID value stored into posts with current userID and get all the posts of the user
    let update = ref.child("posts").queryOrdered(byChild: "userID").queryEqual(toValue: uid)
    update.observe(FIRDataEventType.value, with:  (snapshot) in
           // print(snapshot)

        self.pathToPictures.removeAll()

        if snapshot.key != nil 

        let results = snapshot.value as! [String : AnyObject]

        for (_, value) in results 
            let pathToPostPicture = Pictures()

            if let pathToImage = value["pathToImage"] as? String , let postID = value["postID"] as? String 
                pathToPostPicture.postImageUrl = pathToImage
                pathToPostPicture.postID = postID
                self.pathToPictures.append(pathToPostPicture)
                print("Image and POST ID: \(pathToPostPicture.postImageUrl!)")
                print("Post ID is : \(postID)")

                if FIRAuth.auth()?.currentUser?.uid == uid 
                ref.child("Users_Details").child(uid!).child("profileImageUrl").observeSingleEvent(of: .value, with:  (userSnapshot) in
                    print(userSnapshot)

                    let userIMageUrl = userSnapshot.value as! String
                    pathToPostPicture.postImageUrl = userIMageUrl
                    self.pathToPictures.append(pathToPostPicture)
                    print("This is the image path:" + userIMageUrl + String(self.pathToPictures.count))

                    // Generate the path
                    let newPostRef = ref.child("posts").childByAutoId()
                    let newKey = newPostRef.key as String
                    print(newKey)
                    let updatedUserData = ["posts/\(postID)/pathToImage": pathToPostPicture.postImageUrl]
                    print("This is THE DATA:" , updatedUserData)
                    ref.updateChildValues(updatedUserData as Any as! [AnyHashable : Any])

                )

                

                print(self.pathToPictures.count)

            

            
         else 
            print("snapshot is nill")

        

        self.collectionView?.reloadData()

    )

更新:这就是我的数据库的样子

这是我的数据库:

 "Users_Details" : 
    "aR0nRArjWVOhHbBFB8yUfao64z62" : 
      "profileImageUrl" : "url",
      "userID" : "aR0nRArjWVOhHbBFB8yUfao64z62"
    ,
    "oGxXznrS2DS4ic1ejcSfKB5UlIQ2" : 
      "profileImageUrl" : "url",
      "userID" : "oGxXznrS2DS4ic1ejcSfKB5UlIQ2"
    
  ,
  "posts" : 
    "-KlzNLcofTgqJgfTaGN9" : 
      "fullName" : "full name",
      "interval" : 1.496785712879506E9,
      "normalDate" : "Tue, 06 Jun 2017 22:48",
      "pathToImage" : "url",
      "userID" : "oGxXznrS2DS4ic1ejcSfKB5UlIQ2"
    ,
    "-KlzNXfvecIwBatXxmGW" : 
      "fullName" : "full name",
      "interval" : 1.496785761349721E9,
      "normalDate" : "Tue, 06 Jun 2017 22:49",
      "pathToImage" : "url",
      "userID" : "oGxXznrS2DS4ic1ejcSfKB5UlIQ2"
    ,

让我告诉你它的作用:它循环浏览帖子并找到所有当前用户的帖子。然后它获取每个帖子的图像 url 的路径并将其分配给一个数组。之后,它会找到图像 url 的当前用户路径并用它更新整个数组。现在,我不知道如何使用新值更新数据库。如果有人知道,将不胜感激!

我希望在多个位置进行原子写入。有人可以告诉我如何修复我的代码来做到这一点吗?

它看起来像这样:

 // ATOMIC UPDATE HERE - IF SOMEBODY CAN FIND THE RIGHT WAY OF DOING THAT

                    // Generate a new push ID for the new post
                    let newPostRef = ref.child(byAppendingPath: "posts").childByAutoId()
                    let newPostKey = newPostRef.key
                    // Create the data we want to update
                    let updatedUserData = ["posts/\(newPostKey)": ["pathToImage": self.pathToPictures]] as [String : Any]

                    // Do a deep-path update
                    ref.updateChildValues(updatedUserData)

【问题讨论】:

如果我了解您的代码的作用,您希望它在更新个人资料图片时更新其所有帖子中用户个人资料图片的所有实例?另外,能否请您附上您的数据库结构图? @JenPerson 是的,这正是我想要实现的。我已经用数据库更新了我的问题。 我想不出用这个来更新数据库的方法。 好的,我想我有一个建议,但再次澄清一下:您正在使用相同的确切图像更新来自该用户的每个帖子,这是用户的个人资料图片,对吗? 是的,这是正确的!你有什么想法? @JenPerson 【参考方案1】:

您似乎要下载大量重复数据。虽然数据库的非规范化是一种很好的做法,但我认为在这种情况下,最好不要在每篇文章中包含相同的下载 URL。它不会对少数帖子产生影响,但如果您有数千个用户和数万或数十万个帖子,那么需要下载大量额外数据。相反,您可以有一个包含 uids 作为键和配置文件 imageUrl 作为值的字典。您可以在字典中检查所需的 uid,如果它不存在,请在数据库中查询该用户的 User_Details,然后将它们添加到字典中。当您需要显示图像时,您将从该字典中获取 url。其他人可能对此有更好的建议,所以我欢迎其他想法。

如果您希望在每个帖子中都保留个人资料图片,那么我建议您使用 Cloud Functions for Firebase。您可以创建一个函数,当profileImageUrl 在用户的User_Details 中更新时,然后在其他帖子中更新此条目。目前,Cloud Functions 仅在 Node.js 中可用。如果您不了解 JS,请不要让它成为一种威慑!学习一点 JS 绝对值得。并且这些示例向您展示了您必须知道的尽可能多的 JS 才能开始使用。 查看这些资源:

Getting Started with Cloud Functions for Firebase

GitHub samples

Cloud Functions for Firebase documentation

Writing a Database Trigger

Writing a Cloud Storage Trigger: Part 1

Writing a Cloud Storage Trigger: Part 2

【讨论】:

感谢您的回答,但这并不是让我暂时摆脱困境的事情。做了一些研究,我发现我需要进行原子更新!我用适合我的代码更新了我的问题。您可以看看并帮助新手使用该部分的工作代码吗?正如我所看到的,Firebase 是你的 Jam,所以我提名你比我更聪明。 :)【参考方案2】:

在逻辑上挣扎了几天后,我终于明白了。如果有人会遇到这样的事情,这就是答案。在我的情况下,它是关于当用户更改他的图像时更新当前用户的所有帖子(我的帖子使用非规范化,所以每个图像路径都是不同的)。它将遍历帖子,找到与他的用户 ID 匹配的当前用户帖子 ID,将它们放入数组中,找到 currentUser 图片并使用图像路径更新该数组。最后将更新 Firebase 数据库!

var pathToPictures = [Pictures]()
func updateAllImagesOfCurrentUserInDatabase() 

    //refrences
    let ref = FIRDatabase.database().reference()
    let uid = FIRAuth.auth()?.currentUser?.uid

    //match the user ID value stored into posts with current userID and get all the posts of the user
    let update = ref.child("posts").queryOrdered(byChild: "userID").queryEqual(toValue: uid)
    update.observe(FIRDataEventType.value, with:  (snapshot) in
        self.pathToPictures.removeAll()

        if snapshot.value as? [String : AnyObject] != nil 
        let results = snapshot.value as! [String : AnyObject]

        for (_, value) in results 
            let pathToPostPicture = Pictures()

            if let pathToImage = value["pathToImage"] as? String , let postID = value["postID"] as? String 
                pathToPostPicture.postImageUrl = pathToImage
                pathToPostPicture.postID = postID
                self.pathToPictures.append(pathToPostPicture)
                print("Image and POST ID: \(pathToPostPicture.postImageUrl!)")
                print("Post ID is : \(postID)")

                if FIRAuth.auth()?.currentUser?.uid == uid 
                ref.child("Users_Details").child(uid!).child("profileImageUrl").observeSingleEvent(of: .value, with:  (userSnapshot) in
                    print(userSnapshot)

                    let userIMageUrl = userSnapshot.value as! String
                    pathToPostPicture.postImageUrl = userIMageUrl
                    self.pathToPictures.append(pathToPostPicture)
                    print("This is the image path:" + userIMageUrl + String(self.pathToPictures.count))

                    // Update the Database

                    let postIDCount = pathToPostPicture.postID!
                    let updatedUserData = ["posts/\(postIDCount)/pathToImage": pathToPostPicture.postImageUrl!]
                    print("This is THE DATA:" , updatedUserData)
                    ref.updateChildValues(updatedUserData as Any as! [AnyHashable : Any])

                )
                
                print(self.pathToPictures.count)
            
            
         else 
            print("snapshot is nill - add some data")
        

        self.collectionView?.reloadData()
    )

【讨论】:

以上是关于Firebase - 跨多个位置的原子写入不起作用的主要内容,如果未能解决你的问题,请参考以下文章

我们如何将数据写入firebase实时数据库?即使启用了读/写,但似乎不起作用

具有索引合并 + orderby 的 Firebase 不起作用

具有索引合并(多个属性)+ orderby 的 Firebase 不起作用

跨多个级别填充不起作用

Firebase 连接检测在 60 秒后不起作用

Firebase - 切换到 WebSocket 协议 - 握手不起作用