Swift with nested ForEach or For in - firebase

Fatal error: each layout item may only occur once: file SwiftUI, line 0
2021-04-20 19:17:54.685999-0500 PetGram[17828:1053156] Fatal error: each layout item may only occur once: file SwiftUI, line 0
I can't figure it out. It only crashes on a second user follow. Once you relaunch you can follow and unfollow and it works fine. If you unfollow until you are below 2 and follow another it crashes again. Any help would be great.
func loadFilteredPosts() {
guard let uid = Auth.auth().currentUser?.uid else { return }
FB.USER_COLLECTION.whereField(FB.USER_FOLLOWERS, arrayContains: uid)
.addSnapshotListener { (snapshot, error) in
if let error = error {
print("DEBUG: Error getting followers from user docs \(error.localizedDescription)")
} else {
if let snapshot = snapshot {
self.filteredUsers = snapshot.documents.compactMap { document in
try? document.data(as: User.self)
}
}
self.posts.forEach { post in
self.filteredUsers.forEach { user in
if user.uid == post.ownerUid {
self.filteredPosts.append(post)
}
}
}
}
}
}

Related

Kotlin firebase executed with addOnSuccessListener even if fails

I have this piece of code and it is executed with .continueWith and addOnSuccessListener even if failed.I try with continueWithTask but i dont understand very well Tasks API. Please help me to understand how to do this.
db.collection(customGameName).document().get().continueWith {
if (!gameslist.contains(customGameName)) {
gameslist.add(customGameName)
SavedPreference.setGamesList(this, gameslist)
adapter.notifyDataSetChanged()
}else{
Toast.makeText(this,"$customGameName is in the list already!",Toast.LENGTH_SHORT).show()
}
}.addOnFailureListener {
Toast.makeText(this,"$customGameName not exist!",Toast.LENGTH_SHORT).show()
gameslist.remove(customGameName)
SavedPreference.setGamesList(this, gameslist)
adapter.notifyDataSetChanged()
}
If you have code that you only want to run when the task is successful, add a success listener to the task. That should look something like this:
db.collection(customGameName).document().get()
.addOnSuccessListener { document ->
if (document != null) {
Log.d(TAG, "DocumentSnapshot data: ${document.data}")
if (!gameslist.contains(customGameName)) {
gameslist.add(customGameName)
SavedPreference.setGamesList(this, gameslist)
adapter.notifyDataSetChanged()
}else{
Toast.makeText(this,"$customGameName is in the list already!",Toast.LENGTH_SHORT).show()
}
} else {
Log.d(TAG, "No such document")
}
}.addOnFailureListener {
Toast.makeText(this,"$customGameName not exist!",Toast.LENGTH_SHORT).show()
gameslist.remove(customGameName)
SavedPreference.setGamesList(this, gameslist)
adapter.notifyDataSetChanged()
}
Note that this code is pretty much straight from the Firebase documentation on getting a document in Kotlin, so I recommend spending some more time there.

SwiftUI Firebase - How to query a document then update?

Trying to query a document and then update it in a function in my ViewModel. Trying something like the below, but it doesn't work. Any advice would be appreciated!
func addToFruits(name: String) {
db.collection("fruits").whereField("name", isEqualTo: name)
.getDocument()
.limit(to: 1)
.updateData(["fruits": FieldValue.arrayUnion([name])])
}
func addToRoutine(routine: String, habit: String) {
db.collection("routines").whereField("name", isEqualTo: routine).getDocuments() { (querySnapshot, err) in
if let err = err {
print("Error getting documents: \(err)")
} else {
for document in querySnapshot!.documents {
document.updateData(["habits": FieldValue.arrayUnion([habit])])
}
}
}
}
In the first one, error I get is "Value of type 'Query' has no member 'getDocument'" and not sure how to resolve this. Second one, error I get is "Value of type 'QueryDocumentSnapshot' has no member 'updateData'"
It's not exactly clear what you're attempting to update but here's some quick example code that will read in a user named 'Steve' and update his age to 50. Keep in mind this will read in the FIRST user named 'Steve' and update their age - then when it's run again, will read the NEXT Steve etc etc - that may be what your attempting to do.
func readUsersAndUpdateTheirAgeTo50() {
let users = self.db.collection("users") //self.db points to *my* firestore
users.whereField("name", isEqualTo: "Steve").limit(to: 1).getDocuments(completion: { querySnapshot, error in
if let err = error {
print(err.localizedDescription)
return
}
guard let docs = querySnapshot?.documents else { return }
for doc in docs {
let docId = doc.documentID
let name = doc.get("name")
print(docId, name)
let ref = doc.reference
ref.updateData(["age": 20])
}
})
}
If I just wanted to update all Steve's age to 50, remove the limit
.limit(to: 1)
Note this code is kind of sloppy as since there is a limit of 1, we wouldn't need the loop. Also note that not every Steve is 50 so there should be additional parameters to narrow down which Steve it is - like a uid for example.

Set UI elements after read firebase kotlin

I am trying to read a document from a database in firebase and show the info at the UI. Any idea why is it not working?
Viewmodel:
var leid = MediatorLiveData<Gas>()
init {
initializeDocument()
}
fun initializeDocument(){
mFirestore?.collection("expenditures")?.document("ASfavaftaseacdadf")?.get()?.addOnSuccessListener { document ->
if (document != null) {
Log.d("TAG", "DocumentSnapshot data: ${document.data}")
var gastl = document.toObject<Gas>()!!
leid.value=gastl
} else {
Log.d("TAG", "No such document")
}
}
?.addOnFailureListener { exception ->
Log.d("TAG", "get failed with ", exception)
}
}
After that, I use databinding for the UI. When I try to execute the code, I dont get any log or anything; It is like the function never execute.
Thanks in advance.

Middleware transform to async/await

I started to learn ES6 and I'm transforming my project from ES5 to ES6. I want to ask if it's sense to use async/await in middlewares ? How to use it in this example :
middlewareObj.checkCampground = (req,res,next) =>{
if(req.isAuthenticated()){
Campground.findById(req.params.id, (err, foundCampground) =>{
if(err || !foundCampground){
req.flash("error", "Campground not found");
res.redirect("back");
} else {
if(foundCampground.author.id.equals(req.user._id) || req.user.isAdmin){
next();
} else {
req.flash("error", "You don't have permission to do that");
res.redirect("back");
}
}
});
} else {
req.flash("error", "You need to be logged in to do that");
res.redirect("back");
}
};
When you only have a single asynchronous operation like you do here, you don't gain much (if anything) from switching to await. The bigger benefits come when you need to sequence multiple asynchronous operations and perhaps even have some branching. Then await lets you write much simpler code.
Plus, most of your code here is really just about checking results and getting the right error message back to the user and that doesn't get a lot simpler with await as it's just a bunch of rote checks either way.
Here's an implementation that also attempts to use exceptions to consolidate all the error returns so you don't have as many places where you're doing req.flash() and res.redirect():
middlewareObj.checkCampground = async (req,res,next) => {
try {
if(req.isAuthenticated()) {
throw new Error("You need to be logged in to do that");
}
const foundCampground = await Campground.findById(req.params.id);
if (!foundCampground) {
throw new Error("Campgound not found")
}
if (foundCampground.author.id.equals(req.user._id) || req.user.isAdmin) {
next();
} else {
throw new Error("You don't have permission to do that");
}
} catch(e) {
console.log(e);
req.flash(e.message);
res.redirect("back");
}
};
Here's another alternative without async/await that just attempts to consolidate the error handling a bit. You can't get around the fact that there are three if checks and four possible errors:
middlewareObj.checkCampground = (req,res,next) => {
function error(msg, location = "back") {
req.flash(msg);
res.redirect(location);
}
if(req.isAuthenticated()) {
error("You need to be logged in to do that");
return;
}
Campground.findById(req.params.id).then(foundCampground => {
if (!foundCampground) {
error("Campground not found");
} else if (foundCampground.author.id.equals(req.user._id) || req.user.isAdmin) {
next();
} else {
error("You don't have permission to do that");
}
}).catch(err => {
console.log(err);
error("Database Error - Campground not found");
});
};
Note that in both of these, I make sure and log an actual database error if there is one.

How to by pass Firebase Swift 3 Ambiguous reference to member 'observe(_:with)' error?

I know this question has been asked in the past but, I am unable to find a solution that works for swift 3. Could someone please point me in the right direction. Here is my code:
ref.child(uid).child("flights").observe(.value, with:{ (snapshot: FIRDataSnapshot!) -> Void in
self.messages.append(snapshot)
let row = [IndexPath(row: self.messages.count-1, section: 0) ]
print(snapshot)
self.flightTableView.insertRows(at: row, with: .automatic)
DispatchQueue.main.async {
self.flightTableView.reloadData()
}
})
}
I broke the code up into two statements and it started to work.
let child:FIRDatabaseReference = ref.child(uid).child("flights")
child.observe(.childAdded) { (snapshot:FIRDataSnapshot) in
print(snapshot)
}
Swift 3 & Firebase 3.17.0
This will do the trick, try this code
let ref = FIRDatabase.database().reference().child("uid").child("flights")
ref.observe(.value, with: { (snapshot) in
print("Success get the snapshot \(snapshot)")
// do something with snapshot than
DispatchQueue.main.async {
self.yourTableView.reloadData()
}
}) { (error) in
print("Failed get the snapshot \(error.localizedDescription)")
// do something to handle error
}

Resources