Closed lsamaria closed 5 years ago
I wrote a dictionary
computed property with the intention that this is what would be saved in Firebase. Just those three keys.
So, if the user selected 2 “availability” slots, you have two records, each with those three key/value pairs.
I'm using Firebase Database, wouldn't the previous keys just get written over by the following keys?
For eg the user picks Sunday 6am - 9am and 12pm - 3pm and they also pick Monday 6am - 9am and 12 pm - 3pm
Since the keys are: "dayOfWeek", "startTime", and "endTime" there doesn't seem to be anything that differentiates Sunday from Monday nor the hours.
var dict = [String: Any]()
dict.updateValue("Sunday", forKey: "dayOfWeek")
dict.updateValue(6, forKey: "startTime")
dict.updateValue(9, forKey: "endTime")
dict.updateValue(12, forKey: "startTime") // this just wrote over 6
dict.updateValue(15, forKey: "endTime") // this just wrote over 9
dict.updateValue("Monday", forKey: "dayOfWeek" ) // this just wrote over Sunday
dict.updateValue(6, forKey: "startTime") // this just wrote over 12 from Sunday
dict.updateValue(9, forKey: "endTime") // this just wrote over 15 from Sunday
dict.updateValue(12, forKey: "startTime") // this just wrote over 6
dict.updateValue(15, forKey: "endTime") // this just wrote over 9
someDatabaseRef.updateChildValues(dict)
And in Firebase Database:
@root
|
@someRef
|-"dayOfWeek" : "Monday"
|-"endTime" : 15
|-"startTime" : 12
I’m suggesting a Firebase structure that mirrors the model of the app. Each entry (e.g. Sun 6-9, Sun 12-15, Mon 6-9, Mon 12-15) will be saved as a separate entry (not just updates of the existing entry). In my app, each selected row in the table is an additional entry in the array of Availability
for what the user selected. It’s analogous to a calendar database, where each event on the calendar is a new record. What appears on your calendar is an array of events, presented in a grid. Same thing here. Or at least that’s how I’d do it.
I’m suggesting that you move away from the single record representing all of the windows of availability, but rather an array of the selected “slots” of availability. It seems to be the most flexible approach. This easily supports an evolution in your implementation. E.g. what if you later decide to go to two hour windows? Or one hour windows? You don’t want to have to refactor your data model every time you change what the available slots of time are.
Hi rob, I've been thinking this through for the last couple of hours.
Quickly I'm a self taught developer and never worked on a team before. This is my 3rd app I'm building. I never worked with events before so the concept is new to me. I noticed in one of your comments on SO you said FireStore. I never used SQL before (limitations of self taught) and I know it offers more flexibility, from what I've read FireStore is more similar to that but I always use the Database.
Is this a matter of Firebase Database vs FireStore? It seems that's where part of the problem is occurring because of the Database's flat structure .
If you have the time can you post an example of posting the Sun/Mon examples as data in a dict that would get posted to Fb and then retrieving/sorting the data.
I'm having a hard time understanding how the startTime and endTime won't get written over in the db or better yet in the dictionary itself before it's initially uploaded to the db
No, it’s not a Firestore vs Realtime Database issue. It’s just that you’re updating the same “availability slot” repeatedly. When the user selects a new slot, you want to add a record:
func save(in path: String, values: [String: Any], completion: @escaping (Result<String, Error>) -> Void) {
let ref = Database.database().reference()
let child = ref.child(path).childByAutoId()
child.updateChildValues(values) { error, reference in
guard let key = reference.key else {
completion(.failure(error!))
return
}
completion(.success(key))
}
}
And when the user deselects a slot, you want to remove it:
func remove(in path: String, key: String, completion: @escaping (Result<String, Error>) -> Void) {
let ref = Database.database().reference()
ref.child(path).child(key).removeValue { error, reference in
if let error = error {
completion(.failure(error))
} else {
completion(.success(reference.key!))
}
}
}
That will yield something like the following (where I have the app running in simulator in the foreground, but behind it is the web Firebase console so I can watch what’s going on in the database):
The web-based console is a bit laggy on deletions (I think they do that so you have a chance to see what’s about to be deleted, in red, before it just plain disappears), but ignore that because the actual database interaction is pretty quick. In the above, I refactored it so a tap on a row submits the deletion, but the UI is not updated until the database reports the insertion/deletion, so you can see it’s plenty responsive. You can actually delete right from Firebase and you’ll see it reflected in the app, too.
See Firebase’s Working with Lists of Data on iOS for guidance on how to add/remove items to a list and setting up observers as the server list changes.
I’ve created a branch with Firebase Realtime Database.
Hey rob, I was busy with some personal matters, I couldn't get back to your right away. Now I understand what you meant. I didn't realize each day and time slot was being saved under it's own node. That makes things easier. Now I see how everything can still use the same start time and end time keys.
Thank you very much for your help!
And by the way that video graphic came out really well, I didn't notice the pause/lag until you mentioned it. I know firebase is super lightening quick.
When I finish the app I'll send you a link to see it action :)
Hi rob, I looked over the project last night and I was finally able to track every time slot that was selected in the collectionView's data source array. I did mines differently from yours but you definitely got my wheels turning to get it done, Thanks!
What I came to realize is the matter of posting the data to firebase. How would you format the data to save? I don't mean how to physically save it but the json data itself. For eg there are 7 days and 7 slots per day, if someone was to select all 49 slots there could be up to 49 k/v pairs to reflect that.
Since there are 49 different possibilities I can't think of any other way for the k/v pairs other then below.
And then there is the matter of filtering. The days and hours it should or shouldn't appear in the feed are reflective to what's inside the postModel