laurent espinosa
laurent espinosa

Reputation: 57

Problem with deleting account and documents with Firestore

I want to delete the user account and all of its documents in Firestore, but with asynchronous queries, Firebase deletes the account before all documents.

Because of that I get an auth error because when firestorm delete the lasts documents, the user no longer exist.

db.collection("users").document(self.user.uid).collection("sachets").getDocuments() { (QuerySnapshot, err) in
    if let err = err{
        print("Erreur de lecture : \(err)")
    } else {
        for document in QuerySnapshot!.documents {
            db.collection("users").document(self.user.uid).collection("sachets").document(document.documentID).delete(){ err in
                if let err = err {
                    print("   🔴 Probleme de suppression des docuemnts \(err)")
                } else {
                    print("   🔵 Documents supprimés")
                }
            }
        }
    }
}
self.user?.delete { error in
    if let error = error {
        print("   🔴 Probleme de suppression du compte Utilisateur \(error)")
    } else {
        print("   🔵 Utilisateur supprimé")
    }
}

Someone can tell me how to do ? thanks

Upvotes: 2

Views: 1320

Answers (2)

Jacob Jidell
Jacob Jidell

Reputation: 2792

Alright, I set up a test-project and solve this. You also need to make sure to remove all the data from the user fields. For instance, if you're having name, age etc... at the user node.

First I created a function to fetch the current users uid:

func currentUser() -> String {
    return Auth.auth().currentUser!.uid
}

Then I created a function to remove all the data for the logged in user. This will first remove all the subcollection data and then it will remove the document for the userID.

To handle asynchronous methods you can use DispatchGroup to notify when all the asynchronous calls are done.

One side note: Make sure to NEVER force-unwrap a value if you can't 100% guarantee there are documents. Otherwise, your app will likely crash. To solve this either use guard or if let to solve this problem.

// Where "user" is the result from currentUser()
func removeData(from user: String) {
    db.collection("users").document(user).collection("sachets").getDocuments { (snapshot, error) in
        if let error = error {
            // Handle error
        } else if let documents = snapshot?.documents {
            // Using if let to see if there are documents

            // Time to delete all the subCollection for the user
            self.deleteSubCollectionData(for: user, documents, completion: {

                // Once that done, make sure to delete all the fields on the highest level.
                self.db.collection("users").document(user).delete(completion: { (error) in
                    if let error = error {
                        // Handle error
                    } else {
                        // Delete the account
                        self.deleteAccount()
                    }
                })
            })
        }
    }
}

// This function will remove the subCollectionData
fileprivate func deleteSubCollectionData(for user: String, _ documents: [QueryDocumentSnapshot], completion: @escaping () -> ()) {
    let group = DispatchGroup()
    documents.forEach({
        group.enter()
        self.db.collection("users").document(user).collection("sachets").document($0.documentID).delete(completion: { (error) in
            if let error = error {
                // Handle error
            }
            group.leave()
        })
    })

    // Once the dispatchGroup is done...
    group.notify(queue: .main) {
        completion()
    }
}

And in the end...

func deleteAccount() {
    Auth.auth().currentUser?.delete { (error) in
        if let error = error {
            print(error)
        } else {
            print("Deleted account")
        }
    }
}

If you don't remove all the levels of data, then there still will be data in Firestore.

Upvotes: 2

Crazyrems
Crazyrems

Reputation: 2591

Your getDocuments() method is asynchronous, so you should delete the account only after having deleted the documents.

Just put the user?.delete method inside the getDocuments() callback

db.collection("users").document(self.user.uid).collection("sachets").getDocuments() { (QuerySnapshot, err) in
    if let err = err{
        print("Erreur de lecture : \(err)")
    } else {
        for document in QuerySnapshot!.documents {
            db.collection("users").document(self.user.uid).collection("sachets").document(document.documentID).delete(){ err in
                if let err = err {
                    print("   🔴 Problème de suppression des documents \(err)")
                } else {
                    print("   🔵 Documents supprimés")
                }
            }
        }
    }

    self.user?.delete { error in
        if let error = error {
            print("   🔴 Problème de suppression du compte Utilisateur \(error)")
        } else {
            print("   🔵 Utilisateur supprimé")
        }
    }
}

Upvotes: 0

Related Questions