Incrementing Data in Firestore's Database

Goal:
When someone enters a kitchenID, I want to query the database to ensure a kitchen with that kitchenID exists. If it does, then I want to get the value for the usersConnected key, increment it, and update the value in the database.


Problem Code:
Comes after using a query to get the specific document that matches the kitchenID.

 // Increment usersConnected for that kitchen
usersConnected = querySnapshot!.documents[0].value(forKey: "userConnected") as? Int ?? 0
                                
usersConnected += 1 //Right here it crashes and gives error below:

Terminating app due to uncaught exception ‘NSUnknownKeyException’, reason: '[<FIRQueryDocumentSnapshot 0x6000028c4320> valueForUndefinedKey:]: this class is not key value coding-compliant for the key userConnected.'


Whole Long Function:
I added the whole long function in case you needed context. Please forgive the long function. I am planning to refactor once I get everything working. I kept wanting to refactor earlier, but kept breaking things. And I am SOOOOO close to having a working signUp screen.

func registerAndConnectKitchen() {
        
        if self.email != "" && self.password != "" && self.repass != "" {
            if self.password == self.repass {
                
                let cleanedEmail = email.trimmingCharacters(in: .whitespacesAndNewlines)
                let cleanedPassword = password.trimmingCharacters(in: .whitespacesAndNewlines)
                let kitchenID = kitchenCode.trimmingCharacters(in: .whitespacesAndNewlines)
                
                Auth.auth().createUser(withEmail: cleanedEmail, password: cleanedPassword) { result, error in
                    
                    if error != nil {
                        self.error = error!.localizedDescription
                        self.alert.toggle()
                        return
                    }
                    print("Succeeded in creating user")
                    
                    // Check for valid kitchen code
                    let db = Firestore.firestore()
                    let kitchens = db.collection("kitchens")
                    var usersConnected = 0
                    
                    let query = kitchens.whereField("kitchenID", isEqualTo: kitchenID)
                    
                    query.getDocuments { querySnapshot, error in
                        
                        if error != nil {
                            self.error = error!.localizedDescription
                            self.alert.toggle()
                            return
                        }
                        else if querySnapshot!.documents.isEmpty {
                            self.error = "That kitchen doesn't exist!"
                            self.alert.toggle()
                            return
                        }
                        else {
                            print("Kitchen found. Storing user in database")
                            // Add user to database
                            let users = db.collection("users")
                            
                            users.addDocument(data: [
                                "email" : email,
                                "UID" : result!.user.uid,
                                "kitchenID" : kitchenID
                            ]) { error in
                                
                                if error != nil {
                                    print("User created, but not stored to database!")
                                    print(error!.localizedDescription)
                                }
                                
                                // Increment usersConnected for that kitchen
                                usersConnected = querySnapshot!.documents[0].value(forKey: "usersConnected") as? Int ?? 0
                                
                                usersConnected += 1
                                
                                let kitchen = kitchens.document(kitchenID)
                                kitchen.updateData(["usersConnected" : usersConnected]) { error in
                                    
                                    if error != nil {
                                        print("User stored in database, but kitchen's usersConnected not updated")
                                        print(error!.localizedDescription)
                                    }
                                    
                                    // TODO: Learn what this does - store loggedIn status
                                    // TODO: Store kitchen ID in user defaults?
                                    UserDefaults.standard.set(true, forKey: "status")
                                    NotificationCenter.default.post(name: NSNotification.Name("status"), object: nil)
                                    
                                }
                                
                            }
                        }
                    }
                    
                }
            }
            else {
                self.error = "Passwords must match exactly"
                self.alert.toggle()
            }
        }
        else {
            
            self.error = "Please fill in all the boxes"
            self.alert.toggle()
        }
        
    }

The long function was definitely needed for context! Pretty much just always include that, overall it’s usually pretty difficult to pin down an issue with only a small part of a whole function

The “valueForUndefinedKey” did you spell anything wrong?

I checked but nothing is spelled wrong. that I can see

I’ve realized that it’s not the increment that is causing the error, like I thought. I misinterpreted the breakpoints. The problem is this line:

usersConnected = querySnapshot!.documents[0].value(forKey: "usersConnected") as? Int ?? 0

It’s not the casting that’s the problem because printing this:

print(querySnapshot!.documents[0].value(forKey: "usersConnected"))

Also causes the problem.

If I print the contents of the document:

print(querySnapshot!.documents[0].data())

It looks like this:

[“usersConnected”: 1, “kitchenID”: ZfMnKWYK]

I’m trying to increment that 1. :sob:

Decode this object to get the usersConnected part and then increment that number

Pardon the dumb question, but how do I decode it?

Hi Philomath!

Have you tried this?

let kitchen = db.collection("kitchens").document(kitchenID)
kitchen.updateData([ "usersConnected": FieldValue.increment()])

Documentation reference (bottom of the page, “Increment a numeric value”):
https://firebase.google.com/docs/firestore/manage-data/add-data#increment_a_numeric_value

You could also check for a document’s existence like this:

let kitchen = db.collection("kitchens").document(kitchenID)
kitchen.getDocument { (document, error) in
            if let document = document, document.exists {
                print("document exists")

            } else {
                print("Document does not exist")
            }
        }

Hope this is helpful

THANK YOU THANK YOU THANK YOU!

That was SO much easier. And I’ve saved that documentation for the next time I wonder how to do something with Firebase.

1 Like

Haha my pleasure! The Firebase documentation is really great, definitely recommend checking it out