Maria
Maria

Reputation: 31

How to read nested data from realtime database firebase

My database is structured like this:

{
  "username123" : {
    "6642" : {
      "latitude" : 37.861639,
      "longitude" : -4.785556,
      "name" : "CEPSA"
    }
  }
}

The idea is that every user will have a list of favorite gas stations, identified by their ID (6642 in the example). However, I can't figure out how to get the data. Any help please? Edit: I tried this but it obviously doesn't work since I get back the whole thing, I just can't figure out how to get the id, latitude, longitude and name.

ref.child(user).getData(completion:  { error, snapshot in
        guard error == nil else {
            print(error!.localizedDescription)
            return;
        }
        if let gasStationDict = snapshot.value as? [String:String] {
            guard let id = snapshot.value, let name = gasStationDict["name"], let longitude = gasStationDict["longitude"], let latitude = gasStationDict["latitude"] else { return }
            let gasStation = GasStation(name: name, longitude: longitude, latitude: latitude, favorita: true, id: id)
         }
    });

ref is initialized like this:

var ref: DatabaseReference! = Database.database().reference()

and user is:

guard var user = UserDefaults.standard.string(forKey: "User") else { return }

Upvotes: 0

Views: 170

Answers (1)

Jay
Jay

Reputation: 35657

The main issue is the Firebase structure presented in the question doesn't match the code:

user_id
   gas_station_id
      name

and the code is attempting to read it like this

if let gasStationDict = snapshot.value as? [String:String]

Where the structure is more like this [String: [String: String]] or possibly [String: [String: Int]]

I suggest another solution using .childSnapshot to get deeply nested data. It's easier to read and way easier to maintain

I would also suggest changing the structure. In NoSQL databases it's often best practice to disassociate node keys from the data they contain.

For example, in your structure, 6642 is station ID. What if, in the future the station ID changes? You would literally have to go through your entire database, search for that, delete those nodes and whatever they contain and then re-write them. ugh!

Here's a better structure

{
  "username123" : {
    a_firebase_generated_node_key : { //using .childByAutoId to create
      "latitude" : 37.861639,
      "longitude" : -4.785556,
      "name" : "CEPSA"
      "station_id: "6652"
    }
  }
}

now you can change any aspect of the station and won't have to change any references to it.

Then the code to read and print all of the stations using childSnapshot

func printUsersGasStations() {
    let ref = self.ref.child("gas_stations").child("username123")
    ref.getData(completion: { error, snapshot in
        if let err = error {
            print(err.localizedDescription)
            return
        }
        
        //this next line takes all of the stations and creates
        //   an ordered array of them as DataSnapshots
        let allStationsSnap = snapshot.children.allObjects as! [DataSnapshot]

        for stationSnap in allStationsSnap {
            let stationId = stationSnap.childSnapshot(forPath: "station_id").value as? String ?? "No Station ID"
            let lat = stationSnap.childSnapshot(forPath: "lat").value as? Double ?? 0.0
            let lon = stationSnap.childSnapshot(forPath: "lon").value as? Double ?? 0.0
            let name = stationSnap.childSnapshot(forPath: "name").value as? String ?? "No Name"
            print(stationId, lat, lon, name)
        }
    })
}

Upvotes: 1

Related Questions