RnadomG
RnadomG

Reputation: 165

Firebase and Swift How to pull specific record by child value?

I'm using Firebase with swift (SwiftUI to be exact) and since my DB contains many records (more than 10k records) I'm trying only pull the relevant data from the DB (Otherwise it will pull ALL the data every time which will be a waste).

I think that I should use .indexOn but I don't really know what to do (I don't have much experience with json).

This is the code in SWIFT that I tried using:

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

This is my data structure:

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

and so on...

The blank spots (___:) represents names which were auto generated by Firebase (just random numbers from 0 to the amount of records in the table), and I want to pull by a query the specific record that contains a matching serial.

This is how my rules in Firebase DB looks like:

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

How should I use .indexOn on my Firebase rules? Or is there any other alternative to get what I want?

Thanks in advance.

Update:

I'm trying to get a specific record out of the query. Based on the data structure I specified above, what I'm trying to get is the serial and the date of the child that have a serial number matching to a serial number which I'll input to the query.

Suppose I want to use X8M9320C in the query. What I would like to get is the serial (X8M9320C) and the date back from the table.

Also, the naming for the ___: is an auto generated numbers which are automatically initialized when I upload the json file to Firebase.

Update 2: DB structure The image above represents how the db structure looks.

After some debugging, I saw that after running the query, I'm getting 0 values from the row:

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

The full code:

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)
    })

Upvotes: 1

Views: 222

Answers (1)

Jay
Jay

Reputation: 35667

TL;DR

There was a coding issue which I addressed below and also the string the OP is searching for is this

X8M9320C

but what's stored in Firebase is this

enter image description here

Noting all of the white space (space bar characters) before and after the stored string. The two are not equal which is why my query below won't work on it.

-- Longer answer:

To clarify, Firebase does not have tables; it has key: value pairs which are also called parent and child nodes where the parent is the key and the child is a value, which can also be a pair of key: values.

This sounds like a basic Firebase query which is covered here in the documentation.

Given a structure like the one in your question:

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

Here's the query which will query for serial of X8M9320C and print the date from that node. Keeping in mind that a query could return multiple results we need to iterate over all the returned nodes.

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)")
        }
    })
}

and the output

serial: X8M9320C has a date of 20200513

If you know there will only ever be nothing returned or one returned node (if the serials are guaranteed to be unique for example) you could eliminate the for loop and do this

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)

Upvotes: 2

Related Questions