Home > Software design >  How to get key and value of Firestore mapped object
How to get key and value of Firestore mapped object

Time:03-30

I have an app where users can rate films they have watched, and I want to be able to put these in a tableView. The rating is stored in Firestore, and I want to put both the KEY and value into a Struct so I can access it for the tableView.

However any site/tutorial/stack question I have seen only gets the Maps value, but not the key (in this case, the title name). I can access the value, but only by using the field key, but that is what I am trying to get (see attempt 1)

Firestore Structure

Struct:

struct Rating: Codable {
    var ratedTitle: String
    var ratedRating: Int
}

Variable:

var ratedList = [Rating]()

Load data function (attempt 1):

let dbRef = db.collection("Users").document(userID)
dbRef.getDocument { document, error in
    if let error = error {
         print("There was an error \(error.localizedDescription)")
    } else {
         if let docData = document!.data() {
             let titleRating = docData["Title Ratings"] as? [String: Int]
             let midnightMass = titleRating!["Midnight Mass"]
             print("Rating given to Midnight Mass: \(midnightMass!) stars")
         }
    }
}
//Prints: Rating given to Midnight Mass: 2 stars

Also tried (but I don't know how to get this array onto a tableView and have the first index as the Title label, and the second index a Rating label for each movie in the array) attempt 2:

if let docData = document!.data() {
    let titleRating = docData["Title Ratings"] as? [String: Int]
    self.userRatedList = titleRating!
    print("userRatedList: \(self.userRatedList)")
}
//Prints: userRatedList: ["Midnight Mass": 2, "Bly Manor": 5]

Attempt 3:

if let docData = document!.data() {
    let titleRating = docData["Title Ratings"] as? [String: Int]
    self.ratedList = [Rating(ratedTitle: <#T##String#>, ratedRating: <#T##Int#>)]
    //Don't know what I would put as the ratedTitle String or ratedRating Int.
                    
    self.ratedList = [Rating(ratedTitle: titleRating!.keys, ratedRating: titleRating!.values)]
    //Cannot convert value of type 'Dictionary<String, Int>.Keys' to expected argument type 'String'
    //Cannot convert value of type 'Dictionary<String, Int>.Values' to expected argument type 'Int'
}

CodePudding user response:

Firstly, I am not sure why you need the struct to conform to Codable?

Now, based off what I see, "Title Ratings" is a dictionary with a String key and an Int value. You are overcomplicating this. If you want to access the key and value of each element individually, use a for-in loop.

//Declare your global variable
var ratedList = [Rating]()

//If you are using an if let, there is not need to force unwrap
if let docData = document.data() {
    if let userRatingList = docData["Title Ratings"] as? [String: Int] {
        for (key, value) in userRatingList {
            let rating = Rating(ratedTitle: key, ratedRating: value)
            ratedList.append(rating)
        }

        //reload your tableView on the main thread
        DispatchQueue.main.async {
           tableView.reloadData()
        }

    }
}
  • Related