0

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 }
7
  • 1
    Welcome to SO. We are not a code-writing service but are happy to help with existing code you've attempted. Also, it's important to know what your goal is; 'get the data' is too broad. Please update the question with the code you've attempted and clarify what you're trying do. Commented Mar 16, 2022 at 19:08
  • @Jay I added the bit of code that I tried, I know it could never work but I can't figure out what could. I am trying to get both the id and the nested data inside, but since the ID is unknown to me I can't do ref.child("(user)/(id)") Commented Mar 16, 2022 at 19:16
  • Can you edit the question to show how your ref and user variables are initialized? Commented Mar 16, 2022 at 19:17
  • 1
    Oh - your structure does not match your code; e.g. code is showing snapshot.value as [String: String] and it's actually [String: [String: String]] or [String: [String: Int]. I would personally abandon that practice and use childSnapshot to access nested data - it's a lot easier to read. See my answer here and maybe here Commented Mar 16, 2022 at 19:24
  • 1
    I added an answer that should point you in the right direction - please ask any questions about it if something is unclear. @FrankvanPuffelen done! Commented Mar 17, 2022 at 17:56

1 Answer 1

1

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)
        }
    })
}
Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.