0

This question follows up from this: Join different nodes to observe them at once with firebase. I apologise if it is very similar but I am struggling to solve it in my project.

I have an IngredientData which obtains several ingredients and a property:

{
  "IngredientData": {
    "-KkY92MUZNHXxg4ivGY7": {
      "name": "Onions"
    },
    "-KkY90e7dAgefc8zH3_F": {
      "name": "Peas"
    },
    "-KkY9-HWJANdfhmD-SJ-": {
      "name": "Mushrooms"
    },
    "-KkbWdomTYdpgEDLjC9w": {
      "name": "Eggs"
    },
    "-KkbXOECSCBNAcVaO9rp": {
      "name": "Rice"
    }
  }
}

I then have a RecipeData that contains recipe and inside that are ingredients.

{
  "RecipeData": {
    "-KlApwz5Y-TK_9z1sV1i": {
      "recipeName": "Fried Rice",
      "ingredients": {
        "-KkbWdomTYdpgEDLjC9w": true,
        "-KkbXOECSCBNAcVaO9rp": true,
        "-KkY90e7dAgefc8zH3_F": true
      }
    }
  }
}

I am now trying to get the details of the ingredients inside recipe so I can get the name property. I have a function which iterates inside the recipe's ingredient:

func fetchRecipeIngredients() {

    let databaseRef = FIRDatabase.database().reference().child("RecipeData/recipe/-KlApwz5Y-TK_9z1sV1i/ingredients")

    databaseRef.observeSingleEvent(of: FIRDataEventType.value, with: { snapshot in
        for ingredients in snapshot.children {

            print(snapshot)
        }
    })
}

Here is my Recipe class:

class Recipe {

    var name: String!
    var key: String

    init(from snapshot: FIRDataSnapshot) {

        let snapshotValue = snapshot.value as! [String: Any]

        self.name = snapshotValue["recipeName"] as! String
        self.key = snapshot.key
    }
}

I have two main issues:

  1. Firstly, at the moment I am not sure how to iterate through a specific recipe or whether if that's necessary for what I want to achieve. For now I have hard-coded the recipeID to be able iterate inside it.

  2. How do I get the details of the ingredients when using this fetchRecipeIngredients()

Thanks in advance :)

Chace
  • 561
  • 10
  • 28

1 Answers1

1

Here you go.

Starting with a Firebase Structure

{
  "IngredientData" : {
    "ingredient_0" : {
      "name" : "Onions"
    },
    "ingredient_1" : {
      "name" : "Peas"
    },
    "ingredient_2" : {
      "name" : "Mushrooms"
    },
    "ingredient_3" : {
      "name" : "Tomatoes"
    },
    "ingredient_4" : {
      "name" : "Dough"
    }
  },
  "RecipeData" : {
    "recipe_0" : {
      "ingredients" : {
        "ingredient_0" : true,
        "ingredient_1" : true,
        "ingredient_2" : true
      },
      "name" : "Fried Rice"
    },
    "recipe_1" : {
      "ingredients" : {
        "ingredient_0" : true,
        "ingredient_2" : true,
        "ingredient_3" : true,
        "ingredient_4" : true
      },
      "name" : "Pizza"
    }
  }
}

That's similar to yours

And we have a main function to load in a specific recipe, and then a function to load the ingredients.

   func loadRecipe() {
        let recipiesRef = self.ref.child("RecipeData")
        let recipieToLoadRef = recipiesRef.child("recipe_1")

        recipieToLoadRef.observeSingleEvent(of: .value, with: { snapshot in
            let recipieDict = snapshot.value as! [String:Any]
            let name = recipieDict["name"] as! String
            let ingredientsSnap = snapshot.childSnapshot(forPath: "ingredients")
            print(name)
            self.loadIngredients(ingredientSnap: ingredientsSnap)
        })
    }

    func loadIngredients(ingredientSnap: DataSnapshot) {
        let ingredientsRef = self.ref.child("IngredientData")

        for ingredient in ingredientSnap.children {
            let snap = ingredient as! DataSnapshot
            let ingredientKey = snap.key
            let thisIngredient = ingredientsRef.child(ingredientKey)
            thisIngredient.observeSingleEvent(of: .value, with: { snapshot in
                let ingredientDict = snapshot.value as! [String: Any]
                let ingredientName = ingredientDict["name"] as! String
                print("  \(ingredientName)")
            })
        }
    }
}

and the output

Pizza
  Onions
  Mushrooms
  Tomatoes
  Dough

EDIT

In response to a follow up comment:

If your users want to store their favorites, then create a node

favorites
   recipe_1: true
   recipe_2: true

Observe the /favorites node by .value (which will read all of their favorites in at once. Iterate over the children in the snapshot. The keys will be the recipe node names (recipe_1 and recipe_2). You can then load each recipe name from the node directly (/recipe_1/name) and populate an array that you can use as the datasource for a tableView

Jay
  • 34,438
  • 18
  • 52
  • 81
  • Thank you so much for this answer, it works perfectly. Just one question in regards to identifying a specific recipe. At the moment I've had to hard-code that _ID_ in `recipieToLoadRef ` in order to get the details of the recipe's _ingredients_. However let's say I wanted to create a `favouriteList` for the user to add the recipe how would I specify which recipe to go into and then display on something like a tableView? I have tried using the same approach that you have done for this. If this question is unrelated then don't worry. Thanks again :) – Chace May 29 '17 at 23:21
  • @Chace Glad it helped! I updated the answer with some additional info to address your follow up question. – Jay May 29 '17 at 23:37
  • I appreciate this answer. I have attempted this and I am able to print out the recipe's inside the users favorites. However the part where _You can then load each recipe name from the node directly (/recipe_1/name) and populate an array that you can use as the datasource for a tableView_ is where I am stuck at :/ – Chace May 30 '17 at 00:12
  • @Chace There's a ton of examples here on stack overflow showing how to read data in from Firebase and populate a dataSource. I would suggest searching through those, and then try some code. If you get stuck, post a question! (make sure it's not a duplicate though!) – Jay May 30 '17 at 16:20
  • I know how to populate a datasource in general where I display a list of recipe's. But your example only gets me to print out the recipe's inside users _favorites_. I am able to get the _key_ of the recipes. But now how do I go back to the _RecipeData_ to be able to get the detail of that recipe i.e. name and ingredients. Sorry if there is a better example for this. – Chace May 30 '17 at 17:05
  • 1
    @Chace The code in my answer does both; it gets the recipe and prints the name and then gets the ingredients and prints those as well. If you look at the bottom of the answer, I included the output from the code; Pizza is the name and the ingredients are Onions, Mushrooms, Tomatoes and Dough. – Jay May 30 '17 at 18:14
  • Just want to confirm that I was able to solve my issue with your examples and explanation. Thank you very much for your support! :) – Chace Jun 01 '17 at 00:37