将数据作为阵列发送到Firebase会给我带来错误

时间:2018-05-30 18:13:32

标签: arrays swift firebase firebase-realtime-database

截至目前,我的数据库结构如下 - 这对我有用。但这是我遇到的不幸事件 - 这两个由自动ID分隔的节点实际上是同一个帖子。

如果您看到上一个是我的数据库结构(使用数组),您将看到每个帖子可能有多个图像,日期和计划。哪个效果很好,但在尝试访问索引等时给了我噩梦。所以我转而采用这种更明智的方式。但现在我有问题将这些帖子分组在一起。例如,下面这两个应该完全相同。

当我从我的数据库中读取数据时,我怎样才能确保 - 我将每个自动ID节点与相应的帖子一起分组?即:这两个节点实际上是相同的帖子 - 如你可以告诉他们每个人都有相同的头衔。

   Planit
     -LETR-XJvQsZCOpG-T1N
        Uid: "ZjtJdkjzuxc0mZn4u9TfWsXa9jh2"
        date: "Jun 9, 2018 at 10:00 AM"
        image: "https://img.evbuc.com/https%3A%2F%2Fcdn.evbuc.c..
        plan: "Bike Rodeo, Safety Presentation and Riding Tour o"
        title: "This weekend Plans?"

     -LETR-XKqXf7NY1gh6Jm
        Uid: "ZjtJdkjzuxc0mZn4u9TfWsXa9jh2"
        date: "Jun 11, 2018 at 10:00 AM"
        image: "https://img.evbuc.com/https%3A%2F%2Fcdn.evbuc.c..
        plan: "Fun night out at the Parlor"
        title: "This Weekend Plans?""

我的数据库以前是以这种方式构建的 - 在功能级别上工作得很好,但Firebase程序化主体却错了。我只是把它放进去,所以你可以告诉我实际需要的结构,这些帖子需要以某种方式分组,这样当我从FB读取并将它们加载到表视图中时,相应的数据被存储在一起 - < em>例如 - 1个帖子可以有2个图像,2个计划和2个日期,但只有1个标题(帖子)。

Plant: 
 -LETYTJh1WEHGgGcVCEp
    dates
       0: " "
       1: " "
    images
       0: " "
       1: " "
    plans
       0: " "
       1: " "
    senderId
       0: " "
    title: close

下面是我用来将数据推送到Firebase的函数 - 我循环遍历一个数组,这样每次迭代都会将图像,日期,计划,标题推送到一个&#34;束&#34;。

    for planits in chosenPlanArray {
        DataService.instance.uploadPlanitData(withTitleOfPlan: [planits.nameOfEvent!], 
           withDate: [planits.eventStartsAt!], 
           withImage: [planits.imageForPlan!], 
           withTitle: nameOfPlanit.text!, 
           forUID: (Auth.auth().currentUser?.uid)!, 
           sendComplete: { (isGood) in

            if isGood {

            }
        })
    }

这是我在数据服务类

中的实际实现
func uploadPlanitData(withTitleOfPlan plan: [String], withDate: [String], withImage: [String], withTitle: String, forUID uid: String, sendComplete: @escaping (_ status: Bool) -> ()) {


    _REF_PLANITS.childByAutoId().updateChildValues(["plan" : plan, "date" : withDate, "image": withImage, "title": withTitle, "Uid": uid])
    sendComplete(true)
}

1 个答案:

答案 0 :(得分:1)

我想我理解这个问题,有几种方法可以解决。

1)帖子内的小组

PlanIt
 plans
  -LETR-XJvQsZCOpG-T1N
    Uid: "ZjtJdkjzuxc0mZn4u9TfWsXa9jh2"
    date: "20180609"
    images:
       image_0: "https://img.evbuc.com/https%3A%2F%2Fcdn.evbuc.c.."
       image_1: "https://img.evbuc.com/https%3A%2F%2Fcdn.evbuc.c.."
    plans
       plan_0: "Bike Rodeo, Safety Presentation and Riding Tour o"
       plan_1: "Bike Rodeo, Safety Presentation and Riding Tour o"
    title: "This weekend Plans?"
  -Yjijiioimoifijjiuee
    Uid: "asdaasdas"
    etc

image_0,image_0,plan_0,plan_1等的键将使用childByAutoId创建。

有了这个,你可以加载一次帖子,然后用它获得所有需要的子数据。

请注意,虽然此结构显示为“深层”,但在Firebase NoSQL中通常不鼓励,但您不会对深层数据执行任何查询,并且该数据特定于帖子,所以在这种情况下它很好。

2)对结构进行非规范化/展平

PlanIt
 plans
  -LETR-XJvQsZCOpG-T1N
    Uid: "ZjtJdkjzuxc0mZn4u9TfWsXa9jh2"
    date: "20180609"
    title: "This weekend Plans?"
  -UYijs09as9jiosdijfi
    Uid: "some uid"
    date: "20180609"
    title: "some title"

 all_images:
    -LETR-XJvQsZCOpG-T1N
       image_0: "https://img.evbuc.com/https%3A%2F%2Fcdn.evbuc.c.."
       image_1: "https://img.evbuc.com/https%3A%2F%2Fcdn.evbuc.c.."

 all_plan_details
    -LETR-XJvQsZCOpG-T1N
       detail_0: "Bike Rodeo, Safety Presentation and Riding Tour o"
       detail_1: "Bike Rodeo, Safety Presentation and Riding Tour o"

第二个选项需要初始加载post节点以获取它的密钥,然后一次调用all_images节点加载图像并调用all_plans来获取它的计划。请注意,我使用posts键来引用all_images和all_plans子节点。

这里的想法是我们使用PlanIt子项的键作为all_images和all_plans节点中该节点的引用。 image_0,image_1,plan_0,plan_1是使用.childByAutoId生成的密钥

第二个选项很酷,因为例如,假设您有一个只包含标题和日期列表的tableview,然后当用户点击它时,您可以将图像或计划加载到另一个视图中...此选项将是一次加载的数据少得多,这使得它更易于管理。

修改

为了澄清这个过程,这里是读取计划,图像和计划细节的代码,并根据上述结构将它们打印到控制台。

let mainRef = self.ref.child("PlanIt")
let plansRef = mainRef.child("plans")
let allImagesRef = mainRef.child("all_images")
let allPlanDetailsRef = mainRef.child("all_plan_details")

plansRef.observeSingleEvent(of: .value, with: { snapshot in

 for child in snapshot.children {
     let childSnap = child as! DataSnapshot
     let dict = childSnap.value as! [String: Any]
     let planKey = childSnap.key
     let title = dict["title"] as! String

     let thisPlansImagesRef = allImagesRef.child(planKey)
     let thisPlansDetailsRef = allPlanDetailsRef.child(planKey)
     thisPlansImagesRef.observeSingleEvent(of: .value, with: { imageSnapshot in

         thisPlansDetailsRef.observeSingleEvent(of: .value, with: { planDetailSnapshot in
             //printing is done here because firebase is asynchronous and all data 
             //  will be valid for each node ONLY at this point
             print("plan: \(planKey)  \(title)")
             for imageChild in imageSnapshot.children {
                 let imageChildSnap = imageChild as! DataSnapshot
                 let image = imageChildSnap.value as! String
                 print("  image: \(image)")
             }

             for planDetailChild in planDetailSnapshot.children {
                 let planDetailChildSnap = planDetailChild as! DataSnapshot
                 let planDetail = planDetailChildSnap.value as! String
                 print("  planDetail: \(planDetail)")
             }
         })
     })
  }
})

,输出结果为:

plan: plan_0  This weekend plans
  image: some image for plan_0
  image: another_image for plan_0
  planDetail: some plan detail for plan_0
  planDetail: another plan detail for plan_0
plan: plan_1  Next weekend plans

我在Firebase中添加了一些文本值,以便更清楚输出中的内容。