首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >解析大型Firebase快照

解析大型Firebase快照
EN

Stack Overflow用户
提问于 2021-05-12 18:27:52
回答 2查看 65关注 0票数 0

我正在从Firebase下载一个大型文件结构。但是,当打印键和值时,其中一个子文件夹显示为<__NSArrayM>,我尝试将其转换为String:Any,但它正在崩溃。这是我的代码:

代码语言:javascript
复制
DATABASE.mainOrder.child("incomplete").observe(DataEventType.value, with: { (snapshot) in
        let array = snapshot.value as! [String:[String:Any]]
        for (_, value) in array {
            for number in value {
                if "\(number.key)" == "itemsInOrder" {
                    let items = number.value as! [String:Any]
                    //let items = Array(arrayLiteral: number.value)
                    print("itemsInOrder: \(items)")
                } else {
                    print("\(number.key): \(number.value)")
                }
            }
        }
    })

然而,它正在崩溃,并给了我这个错误:

不能将“__NSArrayM”(0x2037d2608)类型的值转换为“NSDictionary”(0x2037d21d0)。

这是我想要得到的代码:

代码语言:javascript
复制
itemsInOrder: [<__NSArrayM 0x281c060a0>({
    amount = "2";
    length = "5";
    height = "7";
    width = "10";
})]

下面是Firebase json导出

代码语言:javascript
复制
{
"TH000" : {
  "docUUIDStatus" : "Sent",
  "expectedShip" : "May 12, 2021",
  "itemsInOrder" : [ {
    "amountOrdered" : "2000 sq ft",
    "bevel" : "None",
    "floorLength" : "2-8",
    "floorWidth" : "4",
    "specialOrder" : "None",
    "specialOrderLength" : "",
    "status" : "completed"
  } ],
  "orderDate" : "May 11, 2021",
  "orderNumber" : "TH000",
  "orderNumberLowercased" : "th000",
  "orderTime" : "2:30:30 PM",
  "orderType" : "Order",
  "purchaseOrderNumber" : "TH10051",
  "purchaseOrderNumberLowercased" : "th10051",
  "status" : "completed"
 }
}
EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2021-05-14 14:00:58

弗兰克给出的答案是正确的。我想提出另一种办法。

我们已经发现,DataSnapshots非常灵活,而且易于使用--尽可能长时间地将数据作为一个DataSnapshot来保存,尤其是在结构有点深的情况下。当转换到数组和字典时,你会得到这样的结果

代码语言:javascript
复制
[String: [String: [String: Any]]]

这是非常麻烦的工作和疑难解答。

这是按照问题中指定的数据读取的代码。注意,我们从不将任何内容转换为字典,并使用数组来保证从检索到的DataSnapshots中保持排序。

代码语言:javascript
复制
func readData() {
    let ref = self.ref.child("main_order").child("incomplete") //self.ref points to my firebase
    ref.observe(.value, with: { snapshot in //first node will be TH000
        let childSnapArray = snapshot.children.allObjects as! [DataSnapshot]
        for childSnap in childSnapArray {
            print("parent node: \(childSnap.key)")
            let status = childSnap.childSnapshot(forPath: "docUUIDStatus").value as? String ?? "No Status"
            print("  status: \(status)")
            let itemsInOrder = childSnap.childSnapshot(forPath: "itemsInOrder") as DataSnapshot
            let itemSnapArray = itemsInOrder.children.allObjects as! [DataSnapshot]
            print("     \(itemsInOrder.key)")
            for itemChildSnap in itemSnapArray {
                let amount = itemChildSnap.childSnapshot(forPath: "amountOrdered").value as? String ?? "No amount"
                let length = itemChildSnap.childSnapshot(forPath: "floorLength").value as? String ?? "No length"
                let width = itemChildSnap.childSnapshot(forPath: "floorWidth").value as? String ?? "No width"
                let status = itemChildSnap.childSnapshot(forPath: "status").value as? String ?? "No status"
                print("         ", amount, length, width, status)
            }
        }
    })
}

在此过程中,我添加了几个print语句,以显示代码执行顺序。控制台的输出如下

代码语言:javascript
复制
parent node: TH000
  status: Sent
     itemsInOrder
        2000 sq ft 2-8 4 completed

另一件事是存储在itemsInOrder中的数组。还不清楚为什么这是一个数组,通常在实时数据库中应该尽可能避免数组。通常有更好的方法来构造数据。数组不能直接更改--如果要插入或删除元素,则必须读取、修改和写入整个数组。

因此,如果有多个数组元素,那么上面的代码可能需要稍微修改以处理itemsInOrder节点,例如。

票数 0
EN

Stack Overflow用户

发布于 2021-05-13 14:27:16

您在itemsInOrder中拥有的是一个字典数组,因此要从其中获取数据,要么必须在嵌套循环中遍历number,要么使用以下方法提取:

代码语言:javascript
复制
let items = number.value as! [[String:Any]]

因为我觉得第一眼就很难看到双[[,所以我实际上更喜欢这种等价的语法:

代码语言:javascript
复制
let items = number.value as! [Dictionary<String:Any>]

与实际问题无关:在Firebase中,数据结构有点反模式,因为读取任何订单现在也意味着以该顺序加载所有项目。当您想要显示一个订单名称列表时,这会变得很浪费。

数据结构越惯用,它就有两个顶级节点:

  • orders
  • orderItems

在第一个节点中,您将每个订单的属性(如orderTypestatus )存储在order ID下;在第二个节点中,存储订单时间列表,也存储在order ID下。

使用该结构,当前的查询将需要两个步骤:

  1. 一种查询,用于确定具有请求状态的订单ID。然后,为每个订单添加额外的负载,以获取该订单的项目。

这第二步并不像您想象的那么慢,就像Firebase pipelines the requests over a single existing connection一样。

票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/67509175

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档