List nearby GeoFire locations in tableview - ios

Currently, as my codes below shown, my tableview display everything from Firebase. How do I limit the list to what's nearby?
DataService.dataService.BUSINESS_REF.observeEventType(.Value, withBlock: { snapshot in
// A snapshot of the businesses data
self.businesses = []
if let snapshots = snapshot.children.allObjects as? [FDataSnapshot] {
for snap in snapshots {
// Make business array for the tableview
if let postDictionary = snap.value as? Dictionary<String, AnyObject> {
let key = snap.key
let business = Business(key: key, dictionary: postDictionary)
// Show newest business first
self.businesses.insert(business, atIndex: 0)
}
}
}
// Update the table when there is new data
self.searchTableView.reloadData()
})
I'm new to iOS programming and the codes above is from a tutorial, I realise I need to make use of GeoFire's GFQuery objects but I just can't figure out where to put this in my code. Thanks in advance!

Figured it out. Hope someone can suggest the better way of doing this.
func locationManager(manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {
firebase = Firebase(url:"https://myapp.firebaseio.com/")
geoFire = GeoFire(firebaseRef: firebase!.childByAppendingPath("geo"))
let userLocation:CLLocationCoordinate2D = (locationManager.location?.coordinate)!
let center = CLLocation(latitude: userLocation.latitude, longitude: userLocation.longitude)
let span = MKCoordinateSpanMake(0.0125, 0.0125)
let region = MKCoordinateRegionMake(center.coordinate, span)
let regionQuery = geoFire?.queryWithRegion(region)
UIApplication.sharedApplication().networkActivityIndicatorVisible = true
regionQuery!.observeEventType(GFEventTypeKeyEntered, withBlock: { (key: String!, location: CLLocation!) in
// Check for changes in Firebase database
DataService.dataService.BUSINESS_REF.queryOrderedByKey().queryEqualToValue(key).observeEventType(.Value, withBlock: { snapshot in
if let snapshots = snapshot.children.allObjects as? [FDataSnapshot] {
for snap in snapshots {
if let postDictionary = snap.value as? Dictionary<String, AnyObject> {
//let key = snap.key
let business = Business(key: key, dictionary: postDictionary)
self.businesses.insert(business, atIndex: 0)
}
}
}
self.searchTableView.reloadData()
})
})
}

Related

FirebaseDatabase -How to paginate post based on userId

Database layout is
root
posts
-postId_1
-userId
-other data
-postId_2
-userId
-other data
When a user wants to scroll through all posts (location irrelevant) I paginate based on postId using:
let postsRef = Database.database().reference().child("posts")
if startKey == nil {
postsRef.queryOrderedByKey().queryLimited(toLast: 20).observeSingleEvent(of: .value) { [weak self](snapshot) in
guard let firstChild = snapshot.children.allObjects.first as? DataSnapshot else { return }
let arr = snapshot.children.allObjects as! [DataSnapshot]
for child in arr.reversed() {
let postId = child.key
guard let dict = child.value as? [String:Any] else { return }
// create a post, append to datasource ...
}
self?.startKey = firstChild.key
}
else {
postsRef.queryOrderedByKey().queryEnding(atValue: startKey!).queryLimited(toLast: 21).observeSingleEvent(of: .value) { (snapshot) in
// same as above ...
}
}
When I want to query other users based on their location in proximity to the current user I use:
let radius = (10 * 2) * 1609.344 // this is 10 miles
guard let currentLocation = locationManager.location else { return }
let lat = currentLocation.coordinate.latitude
let lon = currentLocation.coordinate.longitude
let location = CLLocation(latitude: lat, longitude: lon)
let region = MKCoordinateRegion(center: location.coordinate, latitudinalMeters: radius, longitudinalMeters: radius)
let geofireRef = Database.database().reference().child("geo")
let geoFire = GeoFire(firebaseRef: geofireRef)
regionQuery = geoFire.query(with: region)
queryHandle = regionQuery?.observe(.keyEntered, with: { [weak self](key: String!, location: CLLocation!) in
let userId = key
let userLocation = location
self?.arrOfUserIds.append(userId)
}
regionQuery?.observeReady({ [weak self] in
self?.paginateBasedOnUserIdReturnedFromRegionQuery()
}
Everything above works fine. The problem is when the regionQuery?.observeReady is called, I have an array of all the userIds in the surrounding 10 mile radius. That can be 1 user or 1000 users and each user can have 1 post or 100+ posts. I can't figure out how to paginate the posts ref based on userId.
Each post has a userId but in the first example above I'm paginating based on postId. I want to paginate the posts ref based on the userIds returned from the regionQuery like
func paginateBasedOnUserIdReturnedFromRegionQuery() {
for userId in arrOfUserIds {
// how to paginate the posts ref using the userId ???
}
}

Accessing variable outside function in Swift

I want to access "posts" outside this function so that I can call tableview.reloaddata() outside the function. The code under calls tableview.reloaddata() everytime a key has entered the qeoquery. I want to only reload it one time. But when I try in viewDidLoad, the "posts" array is empty. What to do?
Posts declared outside function:
var posts = [Post]()
Function:
func fetchData(){
geofireRef = Database.database().reference().child("LOCATION")
geofire = GeoFire(firebaseRef: geofireRef)
let geoQuery = geofire?.query(at: myLoc, withRadius: 5.0)
geoQuery?.observe(.keyEntered, with: { (key: String!, location: CLLocation!) in
print("KEYKEY: \(key)")
let dbRef = Database.database().reference().child("posts")
let query = dbRef.queryOrdered(byChild: "\(key)")
query.observeSingleEvent(of: .value, with: { (snapshot) in
if let snapshot = snapshot.children.allObjects as? [DataSnapshot]{
for snap in snapshot {
if let postDict = snap.value as? Dictionary<String, Any>{
let key = snap.key
let post = Post.init(postKey: key, postData: postDict)
self.posts.append(post)
}
}
}
//self.posts.reverse()
//self.tableView.reloadData()
//print("POSTS: \(self.posts)")
})
})
}
You can either call tableView.reloadData() right after setting your posts variable (like you have commented out), or you can put a didSet observer on your posts variable and reload your tableView after it's set. If you go with that second option you'll want to restructure your parser to set the posts only once, rather than appending items one at a time. That would look something like this:
var posts = [Post]() {
didSet {
self.tableView.reloadData()
}
}
geoQuery?.observe(.keyEntered, with: { (key: String!, location: CLLocation!) in
print("KEYKEY: \(key)")
let dbRef = Database.database().reference().child("posts")
let query = dbRef.queryOrdered(byChild: "\(key)")
query.observeSingleEvent(of: .value, with: { (snapshot) in
if let snapshot = snapshot.children.allObjects as? [DataSnapshot]{
//Create a variable to hold posts until you've parsed all of them
var foundPosts = [Post]()
for snap in snapshot {
if let postDict = snap.value as? Dictionary<String, Any>{
let key = snap.key
let post = Post.init(postKey: key, postData: postDict)
foundPosts.append(post)
}
}
//Set the posts to be all the found posts
self.posts = foundPosts
}
})
})

Swift 3 How to get specific user id in firebase

I am using firebase as backend and I want all user id with status false.
What I am trying in my code:-
ref.child("users").child((Auth.auth().currentUser?.uid)!).child("status").queryOrdered(byChild: "status").queryEqual(toValue : "false").observe(.value) { (snapshot: DataSnapshot) in
if let snapshot = snapshot.children.allObjects as? [DataSnapshot] {
print("SNAPSHOT: \(snapshot)")
for snap in snapshot {
if let postDict = snap.value as? Dictionary<String, AnyObject> {
let key = snap.key
print(key)
print(postDict)
}
}
}
}
Find sample code below. Just verify syntax once.
ref.child("users").observe(DataEventType.value, with: { (snapshot) in
if let snapshot = snapshot.children.allObjects as? [DataSnapshot] {
print("SNAPSHOT: \(snapshot)")
for snap in snapshot {
if let userDict = snap.value as? Dictionary<String, AnyObject> {
if userDict["Status"] as? Bool == false {
let key = snap.key
print(key)
//Add this key to userID array
}
}
}
}
}

Firebase: Access a snapshots children using swift3

I'm trying to get the value of multiple children of my snapshot in order to append my cellDataArray by name and speed.
My code is working for name, but not for speed..
ref = FIRDatabase.database().reference().child("BasicInfo")
let query = ref?.queryOrdered(byChild: "Operator")
query?.observeSingleEvent(of: .value, with: { (snapshot) in
for child in snapshot.children.allObjects as! [FIRDataSnapshot] {
let name = child.key
let speed = child.childSnapshot(forPath: "Speed")
self.cellDataArray.append(cellData(mainText: name, Speed: ""))
self.tableView.reloadData()
}
})
This is my Firebase structure:
Try to access the value property of FIRDataSnapshot to get the Speed.
for child in snapshot.children.allObjects as! [FIRDataSnapshot] {
let name = child.key
if let dic = child.value as? [String:Any], let speed = dic["Speed"] as? Int
let operator = dic["Operator"] as? String {
print(operator)
self.cellDataArray.append(cellData(mainText: name, Speed: "\(speed)"))
}
}
DispatchQueue.main.async {
self.tableView.reloadData()
}

Retrieving and Reading Data as NSArray from Firebase (Swift 3)

I'm working through a course on Udemy to build a chat app with Firebase, Backendless, and Swift. All of the issues (it was written for Swift 2 not 3) I've been able to resolve myself, but this one has me stumped. This function is supposed to retrieve data from the Firebase database, and apparently it was supposed to retrieve it as an NSArray, but it now retrieves it as an NSDictionary, which is making a huge list of errors in the other functions because it's not expecting a dictionary.
func loadRecents() {
firebase.childByAppendingPath("Recent").queryOrderedByChild("userId").queryEqualToValue(currentUser.objectId).observeEventType(.Value, withBlock: {
snapshot in
self.recents.removeAll()
if snapshot.exists() {
let sorted = (snapshot.value.allValues as NSArray).sortedArrayUsingDescriptors([NSSortDescriptior(key: "date", ascending: false)])
}
})
}
I've updated to Swift 3 as far as:
func loadRecents() {
ref = FIRDatabase.database().reference()
let userId = currentUser?.getProperty("username") as! String
ref.child("Recent").queryOrdered(byChild: "userId").queryEqual(toValue: userId).observe(.value, with: {
snapshot in
self.recents.removeAll()
if snapshot.exists() {
let values = snapshot.value as! NSDictionary
}
})
}
Of course, using as! NSArray does not work. Would very much appreciate it if anyone can suggest a method to update this to use Swift 3, sort it by a value in the data, and be able to access it later on. Thanks!
func loadRecents() {
ref = FIRDatabase.database().reference()
let userId = currentUser?.getProperty("username") as! String
ref.child("Recent").queryOrdered(byChild: "userId").queryEqual(toValue: userId).observe(.value, with: {
snapshot in
self.recents.removeAll()
if snapshot.exists() {
let values = snapshot.value as! [String:AnyObject]
}
})}
or you can use also let values = snapshot.value as! [Any]
Hope this will help you, try this code:
func loadRecents() {
let ref = FIRDatabase.database().reference()
let userId = currentUser?.getProperty("username") as! String
ref.child("Recent").queryOrdered(byChild: "userId").queryEqual(toValue: userId).observe(.value, with: {
snapshot in
self.recents.removeAll()
guard let mySnapshot = snapshot.children.allObjects as? [FIRDataSnapshot] else { return }
for snap in mySnapshot {
if let userDictionary = snap.value as? [String: Any] {
print("This is userKey \(snap.key)")
print("This is userDictionary \(userDictionary)")
}
}
})
}

Resources