Reputation: 407
I am creating an iOS app where I have a standard set of user data in my firebase real time database. The user data consists of values such as name, age etc. Here is the structure:
user
- userId1
- name : Bob
- age : 25
- userId2
- name : Rob
- age : 24
- userId3
- name : Dylan
- age : 13
I also have another data named "connections" that has a structure as follows:
connections
- userId1
- userId2 : 1
- userId3 : 1
Let us say the current user ID is userId1. Now, when I press a button, I want to fetch all connections data for the userId1, which is userId2 and userId3. The question here is, how do I look into the "user" structure and get the relevant user information for userId2 and userId3?
In simple words, how do I filter data in a structure based on the data in another structure? Just can't seem to find the right solution online.
I am only able to fetch all the data. Have no clue how to filter the data.
Upvotes: 0
Views: 136
Reputation: 35659
Firebase can be a bit tricky when you first get started so here's some code to go along with the correct answer from Kato.
Conceptually, to begin with you want to know the uid's of this users connections. To do that, since we know this users uid, we can read the connection data directly from the connections node like this.
func readConnections() {
let uid = "userId1"
let thisUsersConnections = self.ref.child("connections").child(uid)
thisUsersConnections.observeSingleEvent(of: .value, with: { snapshot in
let connections = snapshot.children.allObjects as! [DataSnapshot]
for connection in connections {
let connectionUid = connection.key
self.printConnectionInfo(forUserId: connectionUid)
}
})
}
the snapshot that's populated will contain all of the child data of the userId1 node, which is
- userId2 : 1
- userId3 : 1
In this case, I want to read them in the order in which they appear in Firebase so we take that data contained in the snapshot and populate an array.
let connections = snapshot.children.allObjects as! [DataSnapshot]
Note the elements in the connections array are they in themselves DataSnapshots.
That array is iterated over to get each object (a DataSnapshot), and the .key of each snapshot is the uid of each of that users connections. The key is then passed to another function (for clarity) which reads in the user info for the passed in uid and prints the name and age to console.
func printConnectionInfo(forUserId: String) {
let usersRef = self.ref.child("users").child(forUserId)
usersRef.observeSingleEvent(of: .value, with: { snapshot in
let name = snapshot.childSnapshot(forPath: "name").value as! String
let age = snapshot.childSnapshot(forPath: "age").value as! Int
print(name, age)
})
}
Upvotes: 0
Reputation: 40582
First, you aren't filtering data, you are joining data. So having the correct mindset is an important starting point.
Assuming you're not fetching thousands of these at each request (which you shouldn't be in any case), the answer is that it probably doesn't matter. RTDB uses websockets and holds a pipeline open to the server, so requesting them individually or as a single query doesn't make much difference. It's really mostly about the byte count which doesn't change if you fetch each record or all the records in one go. So just fetch each user as needed.
At scale, don't be afraid to duplicate a little data for read efficiency. It's fine if you just need the names of the users to copy them directly into your data in places where you'll be performing large scale reads (in the hundreds of thousands or more).
There's a great series for Firestore that is mostly applicable to RTDB as well, which is a great primer to NoSQL data structures, particularly episodes #3 and #4.
Upvotes: 2