首页 > 解决方案 > Firebase 和 Swift 如何按子值提取特定记录?

问题描述

我正在使用带有 swift 的 Firebase(确切地说是 SwiftUI),并且由于我的数据库包含许多记录(超过 10k 条记录),我试图只从数据库中提取相关数据(否则它每次都会提取所有数据,这将浪费)。

我认为我应该使用 .indexOn 但我真的不知道该怎么做(我对 json 没有太多经验)。

这是我尝试使用的 SWIFT 代码:

ref.child("Items").observeSingleEvent(of: .value, with: { (snapshot) in
        for child in snapshot.children {
            let snap = child as! DataSnapshot
            // Doing stuff here.
        }
})

这是我的数据结构:

tbl (the actual table):
    items:
          ____:
               serial:
               date:
               more parameters...:
          ____:
              serial:
              date:

等等...

空白点 (___:) 表示由 Firebase 自动生成的名称(只是从 0 到表中记录数量的随机数),我想通过查询提取包含匹配序列的特定记录。

这就是我在 Firebase DB 中的规则的样子:

{
   "rules": {
   ".read": true,
   ".write": false
   }
}

我应该如何在我的 Firebase 规则中使用 .indexOn?或者还有其他选择可以得到我想要的吗?

提前致谢。

更新:

我正在尝试从查询中获取特定记录。根据我上面指定的数据结构,我要获取的是序列号与我将输入到查询中的序列号匹配的孩子的序列号和日期。

假设我想在查询中使用 X8M9320C。我想得到的是序列号(X8M9320C)和表中的日期。

此外,___: 的命名是一个自动生成的数字,当我将 json 文件上传到 Firebase 时会自动初始化。

更新 2: 数据库结构 上图表示 db 结构的外观。

经过一些调试,我看到运行查询后,我从行中得到 0 个值:

let childSnaps = snapshot.children.allObjects as! [DataSnapshot]

完整代码:

let serial = "XCM8320CMW"
    let myDataRef = self.ref.child("tbl")
    let itemsRef = myDataRef.child("items")
    let query = itemsRef.queryOrdered(byChild: "serial").queryEqual(toValue: serial)
    query.observeSingleEvent(of: .value, with: { snapshot in
        let childSnaps = snapshot.children.allObjects as! [DataSnapshot]
        guard let firstChild = childSnaps.first else {return}
        let date = firstChild.childSnapshot(forPath: "date").value as? String ?? "No Date"
        print(date)
    })

标签: swiftfirebaseswiftui

解决方案


TL;博士

我在下面解决了一个编码问题,OP正在搜索的字符串就是这个

X8M9320C

但是存储在 Firebase 中的是这个

在此处输入图像描述

注意存储字符串前后的所有空格(空格键字符)。两者不相等,这就是为什么我下面的查询不起作用的原因。

-- 更长的答案:

澄清一下,Firebase 没有表格;它有键:值对,也称为父节点和子节点,其中父节点是键,子节点是值,也可以是一对键:值。

这听起来像是文档中介绍的基本 Firebase查询

鉴于您的问题中的结构:

my_data
   items
      item_0
         serial: "OU812"
         date: "20200427"
         more parameters...:
      item_1
         serial: "X8M9320C"
         date: "20200513"
         more parameters...:

这是查询 X8M9320C 的序列并从该节点打印日期的查询。请记住,查询可能会返回多个结果,我们需要遍历所有返回的节点。

func queryForItem() {
    let serial = "X8M9320C"
    let myDataRef = self.ref.child("my_data")
    let itemsRef = myDataRef.child("items")
    let query = itemsRef.queryOrdered(byChild: "serial").queryEqual(toValue: serial)
    query.observeSingleEvent(of: .value, with: { snapshot in
        let childSnaps = snapshot.children.allObjects as! [DataSnapshot]
        for snap in childSnaps {
            let date = snap.childSnapshot(forPath: "date").value as? String ?? "No Date"
            print("serial: \(serial) has a date of \(date)")
        }
    })
}

和输出

serial: X8M9320C has a date of 20200513

如果您知道永远不会返回任何内容或返回一个节点(例如,如果保证序列是唯一的),您可以消除 for 循环并执行此操作

let childSnaps = snapshot.children.allObjects as! [DataSnapshot]
guard let firstChild = childSnaps.first else {return}
let date = firstChild.childSnapshot(forPath: "date").value as? String ?? "No Date"
print(date)

推荐阅读