skip to Main Content

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)

3

Answers


  1. Chosen as BEST ANSWER

    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.


  2. 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})
    
    Login or Signup to reply.
  3. 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()

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search