I am trying developing an application like Taxi booking and storing data on Firebase.
But, I am facing problem while querying data for RideDetail(History) from Fireb
The question and comments have some different criteria but let me address it at a high level;
The first answer is: Firebase cannot be queried for the value of one child and then ordered by another.
The simple query function expresses that:
let query = ridesRef.queryOrdered(byChild: "cust_id").queryEqual(toValue: "cust id 4")
To accomplish that task, query for the child data you want, in this case all customer id 4 nodes, and then order in code. Here's an example
class RideClass {
var key = ""
var cust_id = ""
var pay_time = ""
init(key: String, cust_id: String, pay_time: String) {
self.key = key
self.cust_id = cust_id
self.pay_time = pay_time
}
}
var rideArray = [RideClass]()
func populateRideArray() {
let usersRef = self.ref.child("ride_details")
let query = usersRef.queryOrdered(byChild: "cust_id").queryEqual(toValue: "cust id 4")
query.observeSingleEvent(of: .value, with: { snapshot in
for child in snapshot.children {
let snap = child as! DataSnapshot
let dict = snap.value as! [String: Any]
let key = snap.key
let custId = dict["cust_id"] as! String
let payTime = dict["pay_time"] as! String
let ride = RideClass(key: key, cust_id: custId, pay_time: payTime)
self.rideArray.append(ride)
}
for ride in self.rideArray { //unsorted example
print(ride.pay_time)
}
self.rideArray.sort { $0.pay_time < $1.pay_time } //sort
for ride in self.rideArray { //sorted example
print(ride.pay_time)
}
})
}
In this example, we create a RideClass which stores some info about the ride, and then an array of rides which could be used as a tableView dataSource.
Then query for all rides that are for cust id 4. We have a loop to show what was retreived unsorted and then this little gem
self.rideArray.sort { $0.pay_time < $1.pay_time }
which sorts the ride array in place by pay_time, which answers the question.
Suppose though, there are 100,000 ride child nodes. Loading in all of that data and sorting in code could be challenging memory wise. What do you do?
We leverage a compound value; along with the child nodes of cust_id and pay_time, we also include id_time. Here's a possible structure:
"ride_details" : {
"ride_0" : {
"cust_id" : "cust id 4",
"id_time" : "cust id 4_172200",
"pay_time" : "172200"
},
"ride_1" : {
"cust_id" : "cust id 2",
"id_time" : "cust id 2_165500",
"pay_time" : "165500"
},
"ride_2" : {
"cust_id" : "cust id 1",
"id_time" : "cust id 1_182300",
"pay_time" : "182300"
},
"ride_3" : {
"cust_id" : "cust id 3",
"id_time" : "cust id 3_131800",
"pay_time" : "131800"
},
"ride_4" : {
"cust_id" : "cust id 4",
"id_time" : "cust id 4_132200",
"pay_time" : "132200"
}
},
and then some code to read in the cust id 4 nodes in the correct order
let ridesRef = self.ref.child("ride_details")
let query = ridesRef.queryOrdered(byChild: "id_time")
.queryStarting(atValue: "cust id 4_")
.queryEnding(atValue: "cust id 4_\\uf8ff")
query.observeSingleEvent(of: .value, with: { snapshot in
for child in snapshot.children {
let snap = child as! DataSnapshot
let dict = snap.value as! [String: Any]
let key = snap.key
let custId = dict["cust_id"] as! String
let payTime = dict["pay_time"] as! String
let ride = RideClass(key: key, cust_id: custId, pay_time: payTime)
self.rideArray.append(ride)
}
for ride in self.rideArray { //unsorted example
print(ride.pay_time)
}
})
Two things to note:
The snapshot must be iterated over to maintain the child sequence
"\uf8ff" is a character at a very high code level in Unicode - because of that it encompasses all of the preceeding characters.
There are two basic approaches that may work for your requirements:
construct a query that orders by payment_time
, limits to include only the first 10 records, then holds a reference to the 10th record so that you can make subsequent pagination calls with the queryStartingAtValue
filter.
Setup a firebase cloud function with a database trigger listening to the payment_time
node, such that every time your empty sting is updated with a value in the database you transform the data so that it's organized in such a way that makes it trivial to consume for your needs here. For example - I would organize the new data at a path that looks like this: customer_ride_details/{{customer_id}}/{{ride_id}}
. And since you are triggering the function when you replace the payment_time
empty string with a timestamp. The keys should be ordered already for you to consume. You will still need to manage your pagination like we did with option 1.