GeoFire with Swift - swift

I plan to use GeoFire to filter my firebase data based on location. Not sure how to get started with this because I just started developing. I have a pic and a caption etc that I create in one Class with:
#IBAction func shareDidTap(_ sender: Any) {
if let image = image, let caption = textView.text {
let newMedia = Media(type: "image", caption: caption, createdBy: user, image: image)
newMedia.save(completion: { (error) in
if let error = error {
self.alert(title: "Oops!", message: error.localizedDescription, buttonTitle: "OK")
} else {
self.user.share(newMedia: newMedia)
in a separate "User" class (MVC) I save it into Firebase with
func share(newMedia: Media) {
DatabaseReference.users(uid: uid).reference().child("media").childByAutoId().setValue(newMedia.uid)
}
Where do I instantiate the GeoFire reference? Do I have to use Core Location to get my own Lat and Lon? Any help would be appreciated. Thank you.

Adding GeoFire
Install with pods
pod 'GeoFire', :git => 'https://github.com/firebase/geofire-objc.git'
Then import to project import GeoFire
Create a reference to it using
let rootRef = Database.database().reference()
let geoRef = GeoFire(firebaseRef: rootRef.child("user_locations"))
To get the current user location you can use Location manager via cocoa pods: https://github.com/varshylmobile/LocationManager
I am guessing you want the media saved on the database to have a location. You then use GeoFire to save the location using GeoFire.setlocation
Call this when you save your post to the database, GeoFire handles the database structure of adding locations using your post ID.
an example:
geoFire!.setLocation(myLocation, forKey: userID) { (error) in
if (error != nil) {
debugPrint("An error occured: \(error)")
} else {
print("Saved location successfully!")
}
}
You then query the database of locations using CircleQuery
You can give a radius of how far you want to query the database within from a given location (user location)
an example:
let query = geoRef.query(at: userLocation, withRadius: 1000)
query?.observe(.keyEntered, with: { key, location in
guard let key = key else { return }
print("Key: " + key + "entered the search radius.")
})
A really good tutorial that I used was:
https://www.youtube.com/watch?v=wr19iKENC-k&t=600s
Look on their channel and query GeoFire for other videos that might help you further.

Related

How to grab data from Firebase Realtime Database and return it in a function in Swift

i am currently working on a project where users have accounts with information about them. And I want that every client can get and load the data with just the ID of the target. I wanted to solve this with a function, but i don't know how to return the data, I hope you can help me!
Screenshot Firebase
func getUserData(targetID: String)->String{
let db = Database.database(url: "link")
db
.reference()
.child("users")
.child(targetID)
.child("/username")
.getData(completion: { error, snapshot in
guard error == nil else {
print(error!.localizedDescription)
return;
}
let userName = snapshot.value as? String ?? "null";
});
return userName //won't work, but how can I make it work?
}

Swift + Firebase. Accessing current user's document

My current firebase structure is Collection of Users which then have a subcollection of habits. For a given user, I want them to be able to add to their own collection of routines. however, running into an issue. When I run the function below, it just creates a separate user with a separate routine. How would I tie a new routine to a current authenticated user?
func addData(routineMsg: String){
let db = Firestore.firestore()
let user = db.collection("users").document()
let routine = db.collection("users").document("GzsHAHq1P0uXGdlYwF8P").collection("routines").document()
routine.setData(["id": routine.documentID, "routine": routineMsg]) { err in
if err != nil {
print((err?.localizedDescription)!)
return
}
}
}
Right now, the code shows how I hard-code it to a certain document (GzsHAHq1P0uXGdlYwF8P), but would like to be able to determine the document dynamically by user
let user = db.collection("users").document()
By not passing document() an argument, what you are doing is creating a new document reference with an auto-generated document ID. What you want to do is pass the method with a string that locates the user's document. Ideally, this would be the user's ID:
guard let uid = Auth.auth().currentUser?.uid else {
return
}
let userDocRef = db.collection("users").document(uid)
From there, to generate random document IDs in the subcollection, do what you were doing before:
func addData(routineMsg: String) {
guard let uid = Auth.auth().currentUser?.uid else {
return
}
let db = Firestore.firestore()
let userDocRef = db.collection("users").document(uid)
let routineDocRef = userDocRef.collection("routines").document()
routineDocRef.setData([
"id": routineDocRef.documentID,
"routine": routineMsg
]) { error in
if let error = error {
print(error)
}
}
}

having problems in adding more than 1 information in the same child firebase

I want to achieve this:
This is my current database. It only shows 1 information but it should be showing 3 messages:
// loading the info onto firebase database
let uid = Auth.auth().currentUser?.uid
let ref = Database.database().reference()
ref.child("workout").observeSingleEvent(of: .value, with: { (snapshot) in
print("Got Snapshot")
print(snapshot.childrenCount)
let chilidCount = snapshot.childrenCount
print(chilidCount)
let post:[String:String] = ["\(chilidCount + 1)": textField.text!]
print(post)
ref.child("workout").child(uid!).setValue(post)
})
self.tableView.reloadData()
This is my code so far. I tried looking at other previous question from StackOverflow and also looked at firebase documentation but could not find anything useful.
This is my tableview
Try making a dictionary of the values you want to upload to your FIR Database.
I assume you want to upload the values to your database in a "workout" folder, and in that upload values for each user. You should do the following:
let uid = Auth.auth().currentUser?.uid
let ref = Database.database().reference()
//Reference to the location where the messages get saved to
let userWorkoutRef = ref.child("workout").child(uid!)
userWorkoutRef.observeSingleEvent(of: .value, with: { (snapshot) in
// Get the number of messages
let messagesCount = snapshot.childrenCount
//Making a dictionary: the key is the current number of messages plus one, the value is the current text entered in the text field
let valueToUpload = ["\(messagesCount + 1)": textField.text!]
//Uploading the dictionary to the database
userWorkoutRef.updateChildValues(valueToUpload) { (err, ref) in
if err != nil {
print(err!.localizedDescription)
return
} else {
print("success uploading data to db!")
}
}
}

Swift saving new comments using CloudKit

I'm trying to make an app which stores a user's comment on CloudKit and then shows it to the other users. User simply enters his/her comment on a text field and clicks on a submit button to submit his/her comment (just like a restaurant app). However, I can't seem to find the correct way no matter what I try. Here is my code, I'd be very glad for any help as I've been stuck on this problem for some time now. Thank you very much in advance!
#IBAction func OnSubmitTouched(_ sender: UIButton) {
if (textField.text != ""){
let newComment = CKRecord(recordType: "Users")
let publicDB = CKContainer.default().publicCloudDatabase
newComment.setValue(textField.text!, forKey: "comment")
publicDB.save(newComment){
rec ,err in
if let error = err {
print(err.debugDescription)
return
}
publicDB.fetch(withRecordID: newComment.recordID){
rec, err in
print(rec!["comment"]!)
return
}
}
let predicate = NSPredicate(value: true)
let query = CKQuery(recordType: "comment", predicate: predicate)
let operation = CKQueryOperation(query: query)
var commentRecords: [CKRecord] = []
operation.recordFetchedBlock = { record in
commentRecords.append(record)
}
operation.queryCompletionBlock = { cursor, error in
print(commentRecords)
}
CKContainer.default().publicCloudDatabase.add(operation)
}
}
You are getting a permission error because Users is a protected record type that CloudKit creates automatically for users of your app. You should name it something else and then it should work.
For example, you could make a Comment record type. This might need a field that references the current user. You can get the current userID with:
CKContainer fetchUserRecordIDWithCompletionHandler:
Here is the Apple documentation for this method.
It is also possible to use the Users record type, but you would have to find the existing userID from CloudKit as above then build a record around that.
See also this answer.

Iterate through emails in Firebase - Swift

I am currently trying to iterate through all user emails in firebase, however, whenever I run my code, and try to add the "test#gmail.com" user, there is an error. However, when I try to add my current user's email address, "test1#gmail.com", there is a success.
Below is a snippet of my code demonstrating this. B
Below is also an image showing the structure of my current database.
Note that each user's email is under a unique userID under the "users" part of the database.
Iterating through email snippet.
func searchEmails() {
var ref : DatabaseReference
let currentUserID = Auth.auth().currentUser?.uid
ref = Database.database().reference()
let userRef = ref.child("users")
userRef.observeSingleEvent(of: .value, with: { snapshot in
let enumerator = snapshot.children
while let rest = enumerator.nextObject() as? DataSnapshot {
userRef.child(rest.key).child("email").observe(.value, with: { snapshot in
print(snapshot.value!)
// print("Other rest is this \(otherRest.value!) value")
if(snapshot.value as? String == self.shareEmail.text) {
SVProgressHUD.showSuccess(withStatus: "Request sent to user!")
}
else {
SVProgressHUD.showError(withStatus: "Email not valid.")
}
})
}
})
SVProgressHUD.dismiss()
}
Why don't you try this, Might turn out to be much less headache.. :-
if self.shareEmail.text != "" && self.shareEmail.text.isEmpty == false{
Database.database().reference().child("users").queryOrdered(byChild: "email").queryEqual(toValue: "somemail").observe(.value, with: {(Snapshot) in
if Snapshot.exists(){
// The email that you have been searching for exists in the
// database under some particular userID node which can
// be retrieved from ....
print(Snapshot)
}else{
// No such email found
}
}, withCancel: {(error) in
// Handle any error occurred while making the call to firebase
})
}else{
//Your textfield must not be empty;.... Handle that error
}
Note : This is only gonna work if Firebase Security rules allow it... so you might have to work on that on your console... Good luck!