Im trying to get document from firestore collection for each user , for example let say if user logged in with this email "Hola#example.com" , i want to get document from collection named "Hola" , and if user logged in with this email "Hi#example.com" i want to get document from "Hi" collection i tried this code but it didn't work fine .
import UIKit
import FirebaseFirestore
import Firebase
class orderTableViewController: UIViewController, UITableViewDelegate, UITableViewDataSource, UITextFieldDelegate {
#IBOutlet var order: UITableView!
var db: Firestore!
var firstName = [String]()
var lastName = [String]()
override func viewDidLoad() {
super.viewDidLoad()
db = Firestore.firestore()
let v = logInViewController()
if v.userNameField?.text == “Hi#example.com” {
loadData1()
}
if v.userNameField?.text == “Hola#example.com” {
loadData2()
}
}
func loadData1() {
db.collection(“Hi”).getDocuments()
{
(querySnapshot, err) in
if let err = err
{
print("Error getting documents: \(err)");
}
else
{
var count = 0
for document in querySnapshot!.documents {
count += 1
print("\(document.documentID) => \(document.data())");
self.firstName.append(document.get("firstname") as? String ?? "")
self.lastName.append(document.get("lastname") as? String ?? "")
}
}
self.order.reloadData()
}
}
func loadData2() {
db.collection(“Hola”).getDocuments()
{
(querySnapshot, err) in
if let err = err
{
print("Error getting documents: \(err)");
}
else
{
var count = 0
for document in querySnapshot!.documents {
count += 1
print("\(document.documentID) => \(document.data())");
self.firstName.append(document.get("firstname") as? String ?? "")
self.lastName.append(document.get("lastname") as? String ?? "")
}
}
self.order.reloadData()
}
}
is there a simple way to achieve it ?
You can use Firebase auth with the currentUser property.
let user = Auth.auth().currentUser
let email = user.email
then use this email to grab their collection:
db.collection(email).getDocuments()
read more about this here
Related
I did more trial and error and a bit of online research and this is what I came back with:
func presentWelcomeMessage() {
//Get specific document from current user
let docRef = Firestore.firestore()
.collection("users")
.whereField("uid", isEqualTo: Auth.auth().currentUser?.uid ?? "")
// Get data
docRef.getDocuments { (querySnapshot, err) in
if let err = err {
print(err.localizedDescription)
} else if querySnapshot!.documents.count != 1 {
print("More than one document or none")
} else {
let document = querySnapshot!.documents.first
let dataDescription = document?.data()
guard let firstname = dataDescription?["firstname"] else { return }
self.welcomeLabel.text = "Hey, \(firstname) welcome!"
}
}
It works, but am not sure if it is the most optimal solution.
First I should say firstname is not really the best way to store a var. I would recommend using firstName instead for readability. I also recommend getting single documents like I am, rather than using a whereField.
An important thing to note is you should create a data model like I have that can hold all of the information you get.
Here is a full structure of how I would get the data, display it, and hold it.
struct UserModel: Identifiable, Codable {
var id: String
var firstName: String
private enum CodingKeys: String, CodingKey {
case id
case firstName
}
}
import SwiftUI
import FirebaseAuth
import FirebaseFirestore
import FirebaseFirestoreSwift
class UserDataManager: ObservableObject {
private lazy var authRef = Auth.auth()
private lazy var userInfoCollection = Firestore.firestore().collection("users")
public func getCurrentUIDData(completion: #escaping (_ currentUserData: UserModel) -> Void) {
if let currentUID = self.authRef.currentUser?.uid {
self.userInfoCollection.document(currentUID).getDocument { (document, error) in
if let document = document {
if let userData = try? document.data(as: UserModel.self) {
completion(userData)
}
} else if let error = error {
print("Error getting current UID data: \(error)")
}
}
} else {
print("No current UID")
}
}
}
struct ContentView: View {
#State private var userData: UserModel? = nil
private let
var body: some View {
ZStack {
if let userData = self.userData { <-- safely unwrap data
Text("Hey, \(userData.firstName) welcome!")
}
}
.onAppear {
if self.userData == nil { <-- onAppear can call more than once
self.udm.getCurrentUIDData { userData in
self.userData = userData <-- pass data from func to view
}
}
}
}
}
Hopefully this can point you in a better direction of how you should be getting and displaying data. Let me know if you have any further questions or issues.
I made a code that adds likes and shows their number on the screen.
But there is a problem, when you download the application on 2 devices and press the button at the same time, then only one like is counted. How can I fix this without implementing registration?
There is an idea to make fields that will be created for everyone on the phone when the like is pressed and this number will be added to the total, but I do not know how to implement this.
Here's the current code:
struct LikeCounts {
var likecount: String
}
class LikeTextModel: ObservableObject {
#Published var likecounts: LikeCounts!
private var db = Firestore.firestore()
init() {
updateLike()
}
func updateLike() {
db.collection("likes").document("LikeCounter")
.addSnapshotListener { documentSnapshot, error in
guard let document = documentSnapshot else {
print("Error fetching document: \(error!)")
return
}
guard let data = document.data() else {
print("Document data was empty.")
return
}
if let likecount = data["likecount"] as? String {
DispatchQueue.main.async {
self.likecounts = LikeCounts(likecount: likecount)
}
}
}
}
#ObservedObject private var likeModel = LikeTextModel()
if self.likeModel.likecounts != nil{
Button(action:
{self.like.toggle()
like ? addlike(): dellike()
UserDefaults.standard.setValue(self.like, forKey: "like")
}) {
Text((Text(self.likeModel.likecounts.likecount))}
func addlike() {
let db = Firestore.firestore()
let like = Int.init(self.likeModel.likecounts.likecount)
db.collection("likes").document("LikeCounter").updateData(["likecount": "\(like! + 1)"]) { (err) in
if err != nil {
print(err)
return
}
}
}
func dellike() {
let db = Firestore.firestore()
let like = Int.init(self.likeModel.likecounts.likecount)
db.collection("likes").document("LikeCounter").updateData(["likecount": "\(like! - 1)"]) { (err) in
if err != nil {
print(err)
return
}
}
}
Firestore has the ability to reliably increment a value, like this:
db.collection('likes').doc('LikeCounter')
.updateData([
"likecount": FieldValue.increment(1)
]);
I have this way of collecting information.
struct MainText {
var mtext: String
var memoji: String
}
class MainTextModel: ObservableObject {
#Published var maintext : MainText!
init() {
updateData()
}
func updateData() {
let db = Firestore.firestore()
db.collection("maintext").document("Main").getDocument { (snap, err) in
if err != nil{
print((err?.localizedDescription)!)
return
}
let memoji = snap?.get("memoji") as! String
let mtext = snap?.get("mtext") as! String
DispatchQueue.main.async {
self.maintext = MainText(mtext: mtext, memoji: memoji)
}
}
}
}
And such a way of displaying.
#ObservedObject private var viewModel = MainTextModel()
self.viewModel.maintext.memoji
self.viewModel.maintext.mtext
How can I update online without rebooting the view?
Instead of using getDocument, which only gets the document once and doesn't return updates, you'll want to add a snapshot listener.
Here's the Firestore documentation for that: https://firebase.google.com/docs/firestore/query-data/listen
In your case, you'll want to do something like:
db.collection("maintext").document("Main")
.addSnapshotListener { documentSnapshot, error in
guard let document = documentSnapshot else {
print("Error fetching document: \(error!)")
return
}
guard let data = document.data() else {
print("Document data was empty.")
return
}
if let memoji = data["memoji"] as? String, let mtext = data["mtext"] as? String {
self.maintext = MainText(mtext: mtext, memoji: memoji)
}
}
I'm using a list to display injury data that the user has inputted via a form, that is successfully added to Cloud Firestore. I now want to add a delete function that deletes the injury selected in the list.
Here is my Injury Struct:
import SwiftUI
import FirebaseFirestoreSwift
struct Injury: Identifiable, Codable {
#DocumentID var id: String? = UUID().uuidString
var userId: String?
var specificLocation: String
var comment: String
var active: Bool
var injuryDate: Date
var exercises: String
var activity: String
var location: String
}
My InjuriesViewModel:
import SwiftUI
import Firebase
import FirebaseFirestore
import FirebaseFirestoreSwift
class InjuriesViewModel: ObservableObject {
#Published var injuries = [Injury]()
private var db = Firestore.firestore()
func fetchData () {
let userId = Auth.auth().currentUser?.uid
db.collection("injuries")
.order(by: "injuryDate", descending: true)
.whereField("userId", isEqualTo: userId)
.addSnapshotListener{ (querySnapshot, error) in
guard let documents = querySnapshot?.documents else {
print("no documents")
return
}
self.injuries = documents.compactMap { (queryDocumentSnapshot) -> Injury? in
return try? queryDocumentSnapshot.data(as: Injury.self)
}
}
}
}
My InjuryViewModel (here is where the add and delete injury functions are, however I'm not sure how to fill in the document field):
import SwiftUI
import Firebase
class InjuryViewModel: ObservableObject {
#Published var injury: Injury = Injury(id: "", userId: "", specificLocation: "", comment:
"", active: false, injuryDate: Date(), exercises: "", activity: "", location: "")
private var db = Firestore.firestore()
func addInjury(injury: Injury) {
do {
var addedInjury = injury
addedInjury.userId = Auth.auth().currentUser?.uid
let _ = try db .collection("injuries").addDocument(from: addedInjury)
}
catch {
print(error)
}
}
func deleteInjury(injury: Injury) {
db.collection("injury").document(??).delete() { err in
if let err = err {
print("Error removing document: \(err)")
}
else {
print("Document successfully removed!")
}
}
}
func save () {
addInjury(injury: injury)
}
func delete () {
deleteInjury(injury: injury)
}
}
Thanks in advance for your help!
Here's where I'm at:
func addInjury(injury: Injury) {
do {
var addedInjury = injury
addedInjury.userId = Auth.auth().currentUser?.uid
let documentRef = try db.collection("injuries").addDocument(from: addedInjury)
addedInjury.id = documentRef.documentID
print(documentRef.documentID)
}
catch {
print(error)
}
}
func deleteInjury(injury: Injury) {
db.collection("injuries").document(injury.id!).delete() { err in
if let err = err {
print("Error removing document: \(err)")
}
else {
print("Document successfully removed!")
}
}
}
In deleteInjury, you just need to access the documentID of the current Injury that your view model holds:
func deleteInjury(injury: Injury) {
db.collection("injury").document(injury.id).delete() { err in
if let err = err {
print("Error removing document: \(err)")
}
else {
print("Document successfully removed!")
}
}
}
This is my second post in this awesome group, I have work in the past 5 days on how to be able to get data from Firestore and compare this to my current user location. Everything seems to be working well, except when I test my app in real time (with my iPhone). Sometimes it shows the correct place and other times it crashes or shows a random place. I'm working with the where() method to access the data from my Firestore and it seems that it is returning what I need. I feel that my name in my document is not working correctly at the point where I access the information.
Here is my code:
Firebase screenshots:
Place 1
Place 2
//Creating access to locationManager
var locationManager : CLLocationManager!
#IBOutlet weak var latLabel: UILabel!
#IBOutlet weak var lonLabel: UILabel!
#IBOutlet weak var place: UILabel!
#IBOutlet weak var placeImage: UIImageView!
//Storing the pass data that we got from the firt View
var placeName = String()
var latStore = String()
var lonStore = String()
var lonNumberStore = Double()
var latNumberStore = Double()
var fireLonMax = Double()
var fireLatMax = Double()
var fireLonMin = Double()
var fireLatMin = Double()
override func viewDidLoad() {
//Here goes some code to display on the SecondViewController
latLabel.text = latStore
lonLabel.text = lonStore
latMaxRead()
latMinRead()
lonMaxRead()
lonMinRead()
}
//This is my button to test if I am in the correct place
#IBAction func updateLocation(_ sender: UIButton) {
//
if (fireLatMin...fireLatMax).contains(latNumberStore) && (fireLonMin...fireLonMax).contains(lonNumberStore){
print("Is good place",fireLonMin,fireLonMax,fireLatMin,fireLatMax)
place.text = placeName
} else {
print("Is not good place", fireLonMin,fireLonMax,fireLatMin,fireLatMax)
place.text = "Bad"
}
}
func latMaxRead() {
let docRef = Firestore.firestore()
docRef.collection("places")
.whereField("latMax", isGreaterThanOrEqualTo: latNumberStore)
.getDocuments { (snapshot, error) in
if error != nil {
print("Error getting documents: \(String(describing: error))")
} else {
for document in (snapshot?.documents)! {
self.fireLatMax = document.data()["latMax"] as! Double
//This is where I pull the placeName on my Firebase
self.placeName = document.data()["placeName"] as! String
print("Fire latMax:", self.fireLatMax)
}
}
}
}
func latMinRead() {
let docRef = Firestore.firestore()
docRef.collection("places")
.whereField("latMin", isLessThanOrEqualTo: latNumberStore)
.getDocuments { (snapshot, error) in
if error != nil {
print("Error getting documents: \(String(describing: error))")
} else {
for document in (snapshot?.documents)! {
self.fireLatMin = document.data()["latMin"] as! Double
self.placeName = document.data()["placeName"] as! String
print("Fire latMin: ", self.fireLatMin)
}
}
}
}
func lonMaxRead() {
let docRef = Firestore.firestore()
docRef.collection("places")
.whereField("lonMax", isGreaterThanOrEqualTo: lonNumberStore)
.getDocuments { (snapshot, error) in
if error != nil {
print("Error getting documents: \(String(describing: error))")
} else {
for document in (snapshot?.documents)! {
self.fireLonMax = document.data()["lonMax"] as! Double
self.placeName = document.data()["placeName"] as! String
print("Fire lonMax: ", self.fireLonMax)
}
}
}
}
func lonMinRead() {
let docRef = Firestore.firestore()
docRef.collection("places")
.whereField("lonMin", isLessThanOrEqualTo: lonNumberStore)
.getDocuments { (snapshot, error) in
if error != nil {
print("Error getting documents: \(String(describing: error))")
} else {
for document in (snapshot?.documents)! {
self.fireLonMin = document.data()["lonMin"] as! Double
self.placeName = document.data()["placeName"] as! String
print("Fire lonMin : ", self.fireLonMin)
}
}
}
}
I feel and I'm super confident that I'm doing something wrong, either with my Queries, or my placeName.
Results from my console and my simulator:
Result from my console and my simulator
I think the where() method is the one that is not messing around with my result but I'm not quite shure.
If you are comparing location with in some radius in that case it would not work. You should use Firebase GeoFire instead.
GeoFire is under process to come in FireStore once I had words with their guy but right now it is not possible with FireStore. But what you can do is just put your location data inside Firebase and after filtering the location you can again query on FireStore for further data.
You can get some help regarding GeoFire from GeoFire Doc, GeoFire Git and GeoFire Blog.