Firebase's ref().child(stringPath: String) returning the entire top level collection

Viewed 215

I'm trying to retrieve a specific child of my Firebase database using swiftUI. To do that I use the simple expression

func addListeners() {
    let database = Database.database(url: "https://someUrl")
    let ref = database.reference(withPath: "users")
    let currentUserId = "u3Ebr6M3BAbP7PBSYYJ7q9kEe1l2"
    let drivingTowardsRef = database.reference(withPath: "users/\(currentUserId)/drivingTowardsUsers")
    print("Loading data from \(drivingTowardsRef)")
    
    //THIS RIGHT HERE IS CAUSING THE PROBLEM
    ref.observe(.childAdded) { snapshot in
        print("Got TOP LEVEL data for user \(snapshot.key): \(String(describing: snapshot.value))")
    }
    //---------------------------------------
    
    drivingTowardsRef.observe(.childAdded) { snapshot in
        ref.child(snapshot.key).getData { (error, userSnapshot) in
            if let error = error {
                print(error)
            } else {
                print("Got arriving user data \(snapshot.key): \(String(describing: userSnapshot.value))")
            }
        }
    }
}

The function will just return the entire database data EDIT: The function returns the data from the first observer ref top level in this case users/ which in my case has two elements: niixi6iORjNn8gWq6tKvSi3Bxfc2, u3Ebr6M3BAbP7PBSYYJ7q9kEe1l2

Got arriving user data niixi6iORjNn8gWq6tKvSi3Bxfc2: Optional({
niixi6iORjNn8gWq6tKvSi3Bxfc2 =     {
    aproxTime = 0;
    distance = 0;
    latitude = "37.33070704";
    longitude = "-122.03039943";
    parkingMode = searching;
    userId = niixi6iORjNn8gWq6tKvSi3Bxfc2;
    username = testeroNumero;
};
u3Ebr6M3BAbP7PBSYYJ7q9kEe1l2 =     {
    aproxTime = 0;
    distance = 0;
    drivingTowardsUsers =         {
        niixi6iORjNn8gWq6tKvSi3Bxfc2 =             {
            approxTime = 0;
            distance = "560.1447571016249";
        };
    };
    latitude = "37.32984184";
    longitude = "-122.02018095";
    parkingMode = offering;
    userId = u3Ebr6M3BAbP7PBSYYJ7q9kEe1l2;
    username = cleoBadu;
};

The key for the child path I pass him seems to be correct but it's still returning the entire top level collection instead of the single item...

EDIT: The problem seems to be on the first observer which messes up the .getData() of the ref.child(snapshot.key). Is that even possible?

Just commenting out that ref.observe(.childAdded) will automatically make the second ref.child(snapshot.key) behave totally normally What am I missing?

I could get the entire database as a single mega dictionary and then get the child I want from there but it doesn't seem really conventional, especially when google's library offers the possibility to not do that.

EDIT: I added a printing statement that prints the url of the database ref. If I then type in the url on my browser, it redirects me on the FRT database and landing me on the correct object. So the url it's generating is correct and works perfectly fine. Still the object returned by the getData() is the entire db

SN: I removed all codable structs as that is not the problem, so the question is more focused on the actual problem

EDIT: Created a simple view as that. On a clean project it works on my project it doesn't. I guess it's some sort of configuration but's it's hard to look into it.

PROBLEM: Whatever child(string) I pass him it returns the entire top level data either way (replacing so snapshot.key). For example: I pass the key "something" -> all users are returned, I pass the key "" all users are returned

2 Answers

I just tried to reproduce the problem with (mostly) your code and data, but am not getting the same behavior.

I put the equivalent data into a database of mine at: https://stackoverflow.firebaseio.com/68956236.json?print=pretty

And used this code in Xcode 1.2 with Firebase SDK version 8.6.1:

let ref: DatabaseReference = Database.database().reference().child("68956236")
let currentUserId: String = "u3Ebr6M3BAbP7PBSYYJ7q9kEe1l2"

let drivingTowardsRef: DatabaseReference! = ref.child("\(currentUserId)/drivingTowardsUsers");
print("Loading data from \(drivingTowardsRef)")

drivingTowardsRef.observe(.childAdded) { snapshot in
    ref.child(snapshot.key).getData { (error, userSnapshot) in
        if let error = error {
            print(error)
        } else {
        
            do {
                //let parkingUser =  try userSnapshot.data(as: ParkingUser.self)
                print("Got data for user \(snapshot.key): \(String(describing: userSnapshot.value))")
            } catch {
                print("There has been an error while decoding the user location data with uid \(snapshot.key), the object to be decoded was \(userSnapshot). The decode failed with error: \(error)")
            }
        }
    }
}

The output I get is:

Loading data from Optional(https://stackoverflow.firebaseio.com/68956236/u3Ebr6M3BAbP7PBSYYJ7q9kEe1l2/drivingTowardsUsers)

2021-08-27 10:39:09.578043-0700 Firebase10[36407:3458780] [] nw_protocol_get_quic_image_block_invoke dlopen libquic failed

Got data for user niixi6iORjNn8gWq6tKvSi3Bxfc2: Optional({ aproxTime = 0; distance = 0; latitude = "37.32798355"; longitude = "-122.01982712"; parkingMode = searching; userId = niixi6iORjNn8gWq6tKvSi3Bxfc2; username = testeroNumero; })

As far as I can see this behavior is correct, but different from what you get. I hope knowing that I don't see the same behavior, and what versions I use, may be helpful to you.

This is not an issue with Firebase but rather client-side handling of the data returned, You’re expecting a Double within your Codable struct but supplying a String in the other end— Can you try:

public struct ParkingUser: Codable {
    var latitude: String
    var longitude: String
}
Related