I am new to Swift, with a jolted problem. I need to get a list of all documents in the firestore collection. To do this, I use this function:
#Published var chatList: String!
func getDataFromDatabaseListenChat() {
let db = Firestore.firestore()
db.collection("chatRoom").getDocuments() { (querySnapshot, err) in
if let err = err {
print("Error getting documents: \(err)")
} else {
for document in querySnapshot!.documents {
self.chatList = document.documentID
print("\(document.documentID) => \(document.data())")
}
}
}
}
If there are more than one document in the collection, it turns out that the next document overwrites the previous one in the variable and at the output I get one element in the list. Tell me how to add all these documents to the array so that they can be used in the swiftui list
You need
var chatList = [String]()
Then
self.chatList = querySnapshot!.documents.map{$0.documentID}
You should avoid force unwrapping where possible. The previous answer suggests using an array, which is correct. But for safety you should do the following:
var chatList = [String]()
func getDataFromDatabaseListenChat() {
let db = Firestore.firestore()
db.collection("chatRoom").getDocuments() { (querySnapshot, err) in
if let err = err {
print("Error getting documents: \(err)")
} else if let querySnapshot = querySnapshot {
self.chatList = querySnapshot.documents.map { $0.documentID }
}
}
}
Related
So I'll keep it simple. I've seen questions with similar error.
Unexpected non-void return value in void function
But I already defined medicalContent as a string so I don't know what's goin wrong. I just wish to pass the return medicalContent string from the struct to the textEditor in the view. Any input shall be appreciated!
Code:
struct MedicalEdit: View {
#State var medicalContent: String = ""
init(){
fetchCalmStuff()
}
func fetchCalmStuff(){
let user = Auth.auth().currentUser
let uid = Auth.auth().currentUser!.uid
let db = Firestore.firestore()
let ref = db.collection("list").document(uid).collection("notes")
ref.document("medical").setData(["content":"medical content","identity":"medical" ])
db.collection("userslist").document(uid).collection("Themes").whereField("identity", isEqualTo: "medical")
.getDocuments() { (querySnapshot, err) in
if let err = err {
print("Error getting documents: \(err)")
} else {
for document in querySnapshot!.documents {
let data = document.data()
let medicalContent = data["content"] as! String ?? ""
print(medicalContent)
return medicalContent // this is where I get error // that Unexpected non-void return value in void function.
}
}
}
}
var body: some View {
TextEditor(text: $medicalContent)
}
}
EDIT: Also how come it can print medicalContent but cannot return it? I'm kinda confused.
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 am trying to transform this function so that instead of Printing the firstname, it would instead return it. My goal here is to have a return value so that I can attach the output to a textLabel. Therefore I would have:
WelcomeLabel.text = getDocument()
I don't know if this is the right approach, I would appreciate some guidance.
private func getDocument() {
//Get sspecific 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)
return
} else if querySnapshot!.documents.count != 1 {
print("More than one documents or none")
} else {
let document = querySnapshot!.documents.first
let dataDescription = document?.data()
guard let firstname = dataDescription?["firstname"] else { return }
print(firstname)
}
}
}
i am trying to get the current users firstname and type (Welcome, 'firstname') on a textLabel in a view controller
I understand that Firestore loads data asynchronously, but I want to use these data later and in different ViewControllers. Is there any possibility, to save data in array?
func findPlayers (filters: Dictionary<String, Any>) -> [String] {
let reference = dataService.instance.dbF.collection("playersStats")
var query1: Query
var keysArray = [String?] ()
var resultIDs = [String] ()
for key in filters.keys {
if key != "PositionName" {
keysArray.append(key)
}
}
if filters.keys.count == 1 {
if keysArray[0] != nil {
let value = filters[keysArray[0]!] as? Double
query1 = reference.whereField(keysArray[0]!, isGreaterThan: value! )
query1.getDocuments{ (snapshot, err) in
if let err = err {
print("Error getting documents: \(err)")
} else {
for document in snapshot!.documents {
let id = String(document.documentID)
resultIDs.append(id)
}
}
}
}
}
return resultIDs
}
I really expect to see array full of data I want to get.