Swink
Swink

Reputation: 448

Firebase setData not saving to Firestore

Attempting to update values in my database. I checked and the type of ema.updatedIngredients that I'm passing to saveFunctions is a valid type in firestore.

The saveRecipe function works fine if I would use updateData. It deletes the documents as expected, but I know I'm pointing to the right document.

I can also add documents fine, it is when I am deleting an ingredients and updating the data where it doesn't work.

Save Recipe function to Firebase

func saveRecipe(ingredientList: [String: String], currentRecipe: String){
        guard let uid = FirebaseManager.shared.auth.currentUser?.uid else {
            return
        }
        FirebaseManager.shared.firestore
            .collection("users")
            .document(uid)
            .collection("userRecipes")
            .whereField("recipeID", isEqualTo: currentRecipe)
            .getDocuments() { (querySnapshot, err) in
                    if let err = err {
                        print("Error getting documents: \(err)")
                    } else {
                        for document in querySnapshot!.documents {
                            FirebaseManager.shared.firestore
                                .collection("users")
                                .document(uid)
                                .collection("userRecipes")
                                .document(document.documentID)
                                .setData(["ingredientItem" : ingredientList], merge: true)
                                    
                            print("Updated Recipe")
                        }
                    }
                }
            }

Where I call saveFunction

.toolbar{
            ToolbarItem(placement: .navigationBarTrailing){
                    Button(action: {
                        ema.editMode.toggle()
                        //if user is saving when complete is on the button
                        if !ema.editMode {
                        //saving to firestore
                            rm.saveRecipe(ingredientList: ema.updatedIngredients, currentRecipe: recipeID)
                        }
                    }){
                        HStack{
                            Image(systemName: !ema.editMode ? "pencil.circle" : "")
                                    .foregroundColor(.black)
                            Text(!ema.editMode ? "Edit" : "Complete")
                                .foregroundColor(.black)
                            }
                        }
                    }
                }
            }
        }
  

My View

struct RecipeIngredients: View {
    @State private var sheetMode: SheetMode = .quarter
    @State private var sizing = ""
    @State private var description = ""
    
    @ObservedObject var rm = RecipeLogic()
    @ObservedObject var ema: EditModeActive
    
    @Binding var currentRecipeID: String
    @Binding var ingredients: [String: String]
    
    //turn into Ordered Dictionary so I can grab ingredients key
    func turnIntoDictionary(regularDictionary: [String: String]) -> OrderedDictionary <String, String>{
        var dict = OrderedDictionary <String, String> (
            uniqueKeys: regularDictionary.keys,
            values: regularDictionary.values
        )
        dict.sort()
        return dict
    }
    
    private func listContent(for keys: [String]) -> some View {
        ForEach(keys, id: \.self) { key in
            HStack{
                Text(key)
                    .font(.title2)
                    .foregroundColor(.green)
                    .fontWeight(.bold)
                Text(turnIntoDictionary(regularDictionary: ingredients)[key] ?? "default")
                    .font(.title3)
            }
        }
        .onDelete { indexSet in
            if ema.editMode{
                let key = turnIntoDictionary(regularDictionary: ingredients).keys[indexSet.first!]
                self.ingredients.removeValue(forKey: key)
                ema.updatedIngredients = ingredients
            }
        }
    }
   
    var body: some View {
        ZStack{
            VStack{
                if ema.editMode{
                    HStack{
                        TextField("ex. 1 cup", text: $sizing)
                            .font(.body)
                            .padding(.leading, 30)
                           
                        TextField("ex. Chicken Breast", text: $description)
                            .font(.body)
                    }
                    .padding(.top, 25) //set to give space from ingredient/direction section
                    
                    Button(action: {
                        if (sizing != "" && description != ""){
                            ingredients[sizing] = description
                            ingredients[sizing] = description
                            
                            ema.updatedIngredients[sizing] = description
                                sizing = ""
                                description  = ""
                        }
                        
                    })
                       {
                        Image(systemName: "plus.circle.fill")
                            .foregroundColor(.blue)
                            .padding(.leading, 20)
                            .padding(.top, 20)
                            .opacity(!sizing.isEmpty && !description.isEmpty ? 1.0 : 0.5)
                           Spacer()
                              
                    }
                       .padding(.top, -10)
                       .padding(.bottom, 10)
                }
                List{
                    self.listContent(for: Array(turnIntoDictionary(regularDictionary: ingredients).keys))
                  
                }
                .onAppear{
                    ema.updatedIngredients = ingredients
                }
                .listStyle(SidebarListStyle())
            
                }
            }
        }
    }

EDIT: For further confusion, if I print right before calling the function, it prints the correct keys/values.

print(ema.updatedIngredients)

rm.saveRecipe(ingredientList: ema.updatedIngredients, currentRecipe: recipeID)

Upvotes: 2

Views: 866

Answers (3)

krishnaacharyaa
krishnaacharyaa

Reputation: 24910

There are two methods for updating:

1 . set() - Sets data on the document, overwriting any existing data. If the document does not yet exist, it will be created.

2 . update() - Updates data on the document. Data will be merged with any existing document data. If no document exists yet, the update will fail.

== In flutter ==

  • To update a value in the document

    var collection = 
    FirebaseFirestore.instance.collection('collection');
    collection 
     .doc('doc_id') 
     .update({'key' : 'value'}) // <-- Updated data
     .then((_) => print('Success'))
     .catchError((error) => print('Failed: $error'));
    
  • To add a new value to the existing document.

    var collection = 
    FirebaseFirestore.instance.collection('collection');
    collection
      .doc('doc_id')
      .set(yourData, SetOptions(merge: true)); // <-- Set merge to true.
    

So in your case update() is more suited than set()

Upvotes: 0

Mises
Mises

Reputation: 4603

I don't know how in Swift, but in JavaScript you need to pass {merge: true} as a second positional argument into .setData(), and it will update the document like .updateData() does.

Example:

...
.setData(["ingredientItem": ingredientList], {merge: true})

Upvotes: 0

Swink
Swink

Reputation: 448

Almost ashamed to admit the simplicity of this solution. Once I went from setData to updateData it worked as expected.

Figured I would share in case someone runs into a similar issue.

Upvotes: 1

Related Questions