Hi I am trying to limit a feed to the most recent two posts from users. I was reading the Firebase documentation and it said simply to add "queryLimited(toFirst: Int)" and so far it has not been working, my feed still retrieves all the posts from each user. At the very top is where I have implemented the "queryLimited".
Edit
The way my code is right now, it is only limiting the users and not the posts(json tree below) so how can I change it to limit the posts of each user?
func getAllPosts(refreshing: Bool, refreshControl: UIRefreshControl?) {
let ref = Database.database().reference().child("posts").queryLimited(toFirst: 2)
MBProgressHUD.showAdded(to: self.view, animated: true)
ref.queryOrdered(byChild: "businessName").observe(.childAdded, with: { snapshot in
//observeSingleEvent(of: .value, with: { snapshot in
if let dict = snapshot.value as? NSDictionary {
self.feeds = []
for item in dict {
let json = JSON(item.value)
let uid = json["uid"].stringValue
var name: String = json["businessName"].stringValue
let address: String = json["businessStreet"].stringValue
let state: String = json["businessCity"].stringValue
let caption: String = json["caption"].stringValue
let downloadURL: String = json["download_url"].stringValue
let timestamp = json["timestamp"].doubleValue
let date = Date(timeIntervalSince1970: timestamp/1000)
let postID: String = json["postID"].stringValue
let lat = json["businessLatitude"].doubleValue
let long = json["businessLongitude"].doubleValue
let businessLocation = CLLocation(latitude: lat, longitude: long)
let latitude = self.locationManager.location?.coordinate.latitude
let longitude = self.locationManager.location?.coordinate.longitude
let userLocation = CLLocation(latitude: latitude!, longitude: longitude!)
let distanceInMeters: Double = userLocation.distance(from: businessLocation)
let distanceInMiles: Double = distanceInMeters * 0.00062137
let distanceLabelText = String(format: "%.2f miles away", distanceInMiles)
self.uid = json["uid"].stringValue
let usersReference = Database.database().reference(withPath: "users").queryOrderedByKey().queryEqual(toValue: uid)
usersReference.observeSingleEvent(of: .value, with: { snapshot in
if let dict = snapshot.value as? NSDictionary {
let userInfo = dict.allValues[0]
let userJSON = JSON(userInfo)
name = userJSON["name"].stringValue
}
let post = Post(uid: uid, caption: caption, downloadURL: downloadURL, name: name, date: date, address: address, state: state, distance: distanceLabelText, postID: postID)
self.feeds.append(post)
// sort posts by date/distance
self.feeds.sort {$0.date.compare($1.date) == .orderedDescending}
self.feeds.sort {$0.distance.compare($1.distance) == .orderedAscending}
self.feedTableView.reloadData()
})
}
}
if refreshing {
refreshControl?.endRefreshing()
}
MBProgressHUD.hide(for: self.view, animated: true)
})
}
I'm pretty sure that the order query must precede the limit query.
let ref = Database.database().reference().child("posts").queryOrdered(byChild: "businessName").queryLimited(toFirst: 2)
Related
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 ???
}
}
Hi I am doing a firebase call which is a query to check for the same posts related to a NSDictionary value. The snapshot prints the posts that I want but only 1 post is being displayed. I am trying to think of why it is only displaying 1 post but having a tough time with this.
func getAllPosts(refreshing: Bool, refreshControl: UIRefreshControl?) {
MBProgressHUD.showAdded(to: self.view, animated: true)
Database.database().reference().child("posts").child(self.otherUser?["uid"] as! String).queryOrdered(byChild: "uid").queryEqual(toValue: self.otherUser?["uid"] as! String).observe(.childAdded, with: { snapshot in
if snapshot.exists() {
print(snapshot)
if let dictionary = snapshot.value as? [String: AnyObject] {
self.feeds = []
let uid = dictionary["uid"] as? String
let name = dictionary["businessName"] as? String
let address = dictionary["businessStreet"] as? String
let state = dictionary["businessCity"] as? String
let caption = dictionary["caption"] as? String
let downloadURL = dictionary["download_url"] as? String
let timestamp = dictionary["timestamp"] as? Double
let date = Date(timeIntervalSince1970: timestamp!/1000)
let postID = dictionary["postID"] as? String
let lat = Double(dictionary["businessLatitude"] as! String)
let long = Double(dictionary["businessLongitude"] as! String)
let businessLocation = CLLocation(latitude: lat!, longitude: long!)
let latitude = self.locationManager.location?.coordinate.latitude
let longitude = self.locationManager.location?.coordinate.longitude
let userLocation = CLLocation(latitude: latitude!, longitude: longitude!)
let distanceInMeters: Double = userLocation.distance(from: businessLocation)
let distanceInMiles: Double = distanceInMeters * 0.00062137
let distanceLabelText = String(format: "%.2f miles away", distanceInMiles)
let post = Post(uid: uid!, caption: caption!, downloadURL: downloadURL!, name: name!, date: date, address: address!, state: state!, distance: distanceLabelText, postID: postID!)
self.feeds.append(post)
// sort posts by date
self.feeds.sort {$0.date.compare($1.date) == .orderedDescending}
self.feedTableView.reloadData()
}
if refreshing {
refreshControl?.endRefreshing()
}
MBProgressHUD.hide(for: self.view, animated: true)
} else {
print("No Snapshot found")
MBProgressHUD.hide(for: self.view, animated: true)
}
})
}
I am currently trying to plug in a users coordinates from firebase into my function that will then represent these coordinates on my map. I don't know if this has something to do with me changing the coordinates from a string to a double.
An issue could also be that swift is not recognizing mapView as a part of the viewcontroller's class. I used my #IBOutlet weak var map: MKMapView! as a replacement in hopes that the annotations would show.
func retrieveUsers(){
let ref = Database.database().reference()
ref.child("users").queryOrderedByKey().observeSingleEvent(of: .value, with: { snapshot in
let users = snapshot.value as! [String: AnyObject]
self.user.removeAll()
for (_,value) in users {
if let uid = value["uid"] as? String {
if uid != Auth.auth().currentUser!.uid {
let userToShow = User()
if let fullName = value["full name"] as? String, let imagePath = value["urlToImage"] as? String
,let snap = snapshot.value as? [String: Any],
let userLongitude = Double(snap["long"] as! String),
let userLatitude = Double(snap["lat"] as! String)
{
let otherUserLocation:CLLocationCoordinate2D = CLLocationCoordinate2D(latitude: userLatitude, longitude: userLongitude)
let userAnnotation = MKPointAnnotation()
userAnnotation.coordinate = otherUserLocation
userAnnotation.title = fullName
DispatchQueue.main.async {
self.map.addAnnotation(userAnnotation)
}
}
Need help retrieving and setting an image from firebase. I am able to get the right URL for the image, but unsure on how to convert it to an actual picture I can share using the UIActivityViewController. "let titlePost = self.feeds[sender.tag].downloadURL" is what I am using to retrieve the specific image URL from a post from a tableview feed within my app. I have tried giving it a shot but need some help. Thank you
let shareAction = UIAlertAction(title: "Share", style: UIAlertActionStyle.default, handler: {(alert: UIAlertAction!) in
var objectsToShare: [AnyObject]?
let image: UIImage?
let titlePost = self.feeds[sender.tag].downloadURL
if let postURL = URL(string: titlePost) {
let postRequest = URLRequest(url: postURL)
image.setImageWith(postURL, placeholderImage: nil, options: SDWebImageOptions.progressiveDownload, completed: { (imageRequest, imageResponse, error) -> Void in
// failure downloading image
print("Error downloading Firebase post image")
print(error)
})
}
objectsToShare = [titlePost as AnyObject]
let activityViewController = UIActivityViewController(activityItems: objectsToShare!, applicationActivities: nil)
// present the view controller
self.present(activityViewController, animated: true, completion: nil)
})
Where I am pulling the image from
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
if let cell = tableView.dequeueReusableCell(withIdentifier: "feedCell", for: indexPath) as? CustomerPostsViewCell {
let post = feeds[indexPath.row]
let caption = post.caption
let downloadURL = post.downloadURL
let name = post.name
let address = post.address
let state = post.state
let date = post.date
let distance = post.distance
let dateFormatter = DateFormatter()
dateFormatter.dateFormat = "MM-dd-yyyy"
let dateString = dateFormatter.string(from: date)
// Business Name
cell.businessNameLabel.text = name
cell.businessAddressLabel.text = address
cell.businessStateLabel.text = state
cell.businessPostDistanceLabel.text = distance
// caption
cell.captionView.text = caption
// post image
cell.businessPostImage.image = nil
if let postURL = URL(string: downloadURL) {
let postRequest = URLRequest(url: postURL)
cell.businessPostImage.setImageWith(postURL, placeholderImage: nil, options: SDWebImageOptions.progressiveDownload, completed: { (imageRequest, imageResponse, error) -> Void in
// failure downloading image
print("Error downloading Firebase post image")
print(error)
})
}
// set date of post
cell.postTimeLabel.text = dateString
cell.optionsButton.tag = indexPath.row
cell.optionsButton.addTarget(self, action: #selector(optionsButton), for: .touchUpInside)
return cell
}
return UITableViewCell()
}
// MARK: Queries
func getAllPosts(refreshing: Bool, refreshControl: UIRefreshControl?) {
let ref = Database.database().reference().child("posts")
MBProgressHUD.showAdded(to: self.view, animated: true)
ref.queryOrdered(byChild: "businessName").observe(.childAdded, with: { snapshot in
//observeSingleEvent(of: .value, with: { snapshot in
if let dict = snapshot.value as? NSDictionary {
self.feeds = []
for item in dict {
let json = JSON(item.value)
let uid = json["uid"].stringValue
var name: String = json["businessName"].stringValue
let address: String = json["businessStreet"].stringValue
let state: String = json["businessCity"].stringValue
let caption: String = json["caption"].stringValue
let downloadURL: String = json["download_url"].stringValue
let timestamp = json["timestamp"].doubleValue
let date = Date(timeIntervalSince1970: timestamp/1000)
let lat = json["businessLatitude"].doubleValue
let long = json["businessLongitude"].doubleValue
let businessLocation = CLLocation(latitude: lat, longitude: long)
let latitude = self.locationManager.location?.coordinate.latitude
let longitude = self.locationManager.location?.coordinate.longitude
let userLocation = CLLocation(latitude: latitude!, longitude: longitude!)
let distanceInMeters: Double = userLocation.distance(from: businessLocation)
let distanceInMiles: Double = distanceInMeters * 0.00062137
let distanceLabelText = String(format: "%.2f miles away", distanceInMiles)
self.uid = json["uid"].stringValue
let usersReference = Database.database().reference(withPath: "users").queryOrderedByKey().queryEqual(toValue: uid)
usersReference.observeSingleEvent(of: .value, with: { snapshot in
if let dict = snapshot.value as? NSDictionary {
let userInfo = dict.allValues[0]
let userJSON = JSON(userInfo)
name = userJSON["name"].stringValue
}
let post = Post(uid: uid, caption: caption, downloadURL: downloadURL, name: name, date: date, address: address, state: state, distance: distanceLabelText)
self.feeds.append(post)
// sort posts by date/distance
//self.feeds.sort {$0.date.compare($1.date) == .orderedAscending}
self.feeds.sort {$0.distance.compare($1.distance) == .orderedAscending}
self.feedTableView.reloadData()
})
}
}
if refreshing {
refreshControl?.endRefreshing()
}
MBProgressHUD.hide(for: self.view, animated: true)
})
}
Below codes from Google only return a place if I pick one from the list like the one I attached.
My question:
Is there any function available for me to store all the place's detail in a given coordinate? For example, if I have a coordinate of (51.5108396, -0.0922251), how can I get all the information of nearby places? I am not familiar with Json. Is there any example close to what I want? Thanks a lot.
This function placesClient.currentPlaceWithCallback is somehow close to what I want but it cannot use custom coordinate because it uses user's current coordinate.
//https://developers.google.com/places/ios-api/placepicker
let center = CLLocationCoordinate2DMake(51.5108396, -0.0922251)
let northEast = CLLocationCoordinate2DMake(center.latitude + 0.001, center.longitude + 0.001)
let southWest = CLLocationCoordinate2DMake(center.latitude - 0.001, center.longitude - 0.001)
let viewport = GMSCoordinateBounds(coordinate: northEast, coordinate: southWest)
let config = GMSPlacePickerConfig(viewport: viewport)
let placePicker = GMSPlacePicker(config: config)
placePicker?.pickPlaceWithCallback({ (place: GMSPlace?, error: NSError?) -> Void in
if let error = error {
print("Pick Place error: \(error.localizedDescription)")
return
}
if let place = place {
print("Place name \(place.name)")
print("Place address \(place.formattedAddress)")
print("Place attributions \(place.attributions)")
} else {
print("No place selected")
}
})
Fetching nearby places using google maps
Something is changed due to upgraded iOS version.
complete changed code
func fetchPlacesNearCoordinate(coordinate: CLLocationCoordinate2D, radius: Double, types:[String]) {
var urlString = "https://maps.googleapis.com/maps/api/place/nearbysearch/json?key=\("your api key")&location=\(coordinate.latitude),\(coordinate.longitude)&radius=\(radius)&rankby=prominence&sensor=true"
let typesString = types.count > 0 ? types.joinWithSeparator("|") : "food"
urlString += "&types=\(typesString)"
urlString = urlString.stringByAddingPercentEncodingWithAllowedCharacters(NSCharacterSet.URLQueryAllowedCharacterSet())!
UIApplication.sharedApplication().networkActivityIndicatorVisible = true
let session = NSURLSession.sharedSession()
let placesTask = session.dataTaskWithURL(NSURL(string: urlString)!) {data, response, error in
UIApplication.sharedApplication().networkActivityIndicatorVisible = false
if let jsonResult = (try? NSJSONSerialization.JSONObjectWithData(data!, options: NSJSONReadingOptions.MutableContainers)) as? NSDictionary {
let returnedPlaces: NSArray? = jsonResult["results"] as? NSArray
if returnedPlaces != nil {
for index in 0..<returnedPlaces!.count {
if let returnedPlace = returnedPlaces?[index] as? NSDictionary {
var placeName = ""
var latitude = 0.0
var longitude = 0.0
if let name = returnedPlace["name"] as? NSString {
placeName = name as String
}
if let geometry = returnedPlace["geometry"] as? NSDictionary {
if let location = geometry["location"] as? NSDictionary {
if let lat = location["lat"] as? Double {
latitude = lat
}
if let lng = location["lng"] as? Double {
longitude = lng
}
}
}
print("index", index, placeName, latitude, longitude)
}
}
}
}
}
placesTask.resume()
}