Firebase 和 Swift 如何按子值提取特定记录?

Posted

技术标签:

【中文标题】Firebase 和 Swift 如何按子值提取特定记录?【英文标题】:Firebase and Swift How to pull specific record by child value? 【发布时间】:2020-05-20 10:09:18 【问题描述】:

我正在使用带有 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)
    )

【问题讨论】:

.indexOn 与此任务无关。您正在寻找 Query 以获得特定的子节点(或节点)。我们需要更多信息,但要澄清一下,___ 不应是 (1, 2, 3) 等中的随机数 - 它可能是使用 .childByAutoId 生成的密钥,看起来像 -JyisISkjmosis89。如果不是,我们需要知道它是什么。我们还需要知道您具体查询的是什么——您想从数据库中取回什么。请更新问题并提供更多详细信息,我们将进行查看。 将密钥上传到 FireBase 后会自动生成。它实际上是一个数字,代表我认为来自原始 json 文件的索引。我刚刚更新了问题 请在您的问题中提供完整的代码 - 单行代码对我们没有帮助,因为故障出现在之前的代码中。顺便说一下。如果您正在查询字符串X8M9320C,那么您将没有匹配项,因为该字符串不存在。 Howerver 字符串 _____X8M9320C_____ 确实 - 我使用 ____ 来表示空格,因为 cmets 不支持这些。 再次更新:) 对。请参阅我上面的评论,let serial = "XCM8320CMW" 将不返回任何结果,因为您的数据库中不存在该字符串。 【参考方案1】:

TL;DR

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

X8M9320C

但存储在 Firebase 中的是这个

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

-- 更长的答案:

澄清一下,Firebase 没有表格;它有 key: value 对,也称为 parent 和 child nodes,其中 parent 是 key,child 是 value,也可以是一对 key: values。

这听起来像是一个基本的 Firebase 查询,文档中涵盖了 here。

给定一个类似于您问题中的结构:

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)

【讨论】:

感谢您的回答,但它对我不起作用。我不断收到以下错误:“使用未指定的索引。您的数据将在客户端下载和过滤。考虑将 /my_data/Items 处的“.indexOn”:“Serial”添加到您的安全规则中以获得更好的性能”我试图以两种方式实现您发布的代码,但都失败了。无论哪种方式,第二种方式都符合我的需求,因为连续剧应该是独一无二的。你知道我应该怎么做才能解决我遇到的错误吗?谢谢! @RnadomG 这不是错误。使用“.indexOn”提醒提高性能,但这不是必需的,也不会阻止代码工作。我从一个工作项目中提取了该代码,如答案所示,控制台的输出是预期的。请对您的代码进行故障排除,因为“失败”并没有真正给我们太多帮助。为此,请在代码中添加断点并运行它。然后逐行检查变量,直到它发生意外。找到后,用完整且最少的当前代码更新问题,并指出哪一行失败。 再次您好,感谢您的回答,经过快速调试,我认为我找到了问题的根源,我相应地更新了问题

以上是关于Firebase 和 Swift 如何按子值提取特定记录?的主要内容,如果未能解决你的问题,请参考以下文章

Firebase - iOS SDK - 按子值过滤

Swift 5 Firebase 按子/键查询

如何读取 Firebase 子值?

使用 Swift 更新 Firebase 中的子值

xmlslurper 按子值从 xml 中删除节点

如何从 firebase 实时数据库中获取子值和过滤器?