0

This is how my Object classes looks like:

Workout.swift:

class Workout: Object {

    @objc dynamic var date: Date?
    // List of exercises (to-many relationship)
    var exercises = List<Exercise>()

}

Exercise.swift

class Exercise: Object {

    @objc dynamic var name: String?
    // List of sets (to-many relationship)
    var sets = List<Set>()
    var parentWorkout = LinkingObjects(fromType: Workout.self, property: "exercises")
}

Set.swift

class Set: Object {

    @objc dynamic var reps: Int = 0
    @objc dynamic var kg: Double = 0.0
    @objc dynamic var notes: String?
    // Define an inverse relationship to be able to access your parent workout for a particular set (if needed)
    var parentExercise = LinkingObjects(fromType: Exercise.self, property: "sets")

    convenience init(numReps: Int, weight: Double, aNote: String) {
       self.init()
       self.reps = numReps
       self.kg = weight
       self.notes = aNote
    }
}

And I have a workout that is already created:

[Workout {
    date = 2019-12-07 23:26:48 +0000;
    exercises = List<Exercise> <0x281ea5b00> (
        [0] Exercise {
            name = Barbell Biceps Curl;
            sets = List<Set> <0x281eb0090> (
                [0] Set {
                    reps = 10;
                    kg = 40;
                    notes = Light;
                },
                [1] Set {
                    reps = 10;
                    kg = 40;
                    notes = Light;
                },
                [2] Set {
                    reps = 12;
                    kg = 37.5;
                    notes = Hard;
                }
            );
        }
    );
}]

Now that I have a workout that has already been created, how can I add a new exercise to that exact workout, without creating a whole new workout, so I have two exercises registered in that specific workout?

Camile
  • 155
  • 3
  • 10
  • Sounds like you would like to utilize primary keys https://stackoverflow.com/questions/26152254/how-to-set-primary-key-in-swift-for-realm-model – Okhan Okbay Dec 08 '19 at 00:01
  • @OkhanOkbay So each workout should have a primary key? – Camile Dec 08 '19 at 00:09
  • Yes. Realm will automatically update workouts instead of creating a new one – Okhan Okbay Dec 08 '19 at 00:13
  • @OkhanOkbay Do I provide a key for each workout myself? And how do avoid creating a workout with two identical primary keys? – Camile Dec 08 '19 at 00:21
  • Just keep an ID property, assign the workout count to the next workout that you will record to the Realm. Please read docs of Realm about it – Okhan Okbay Dec 08 '19 at 00:24
  • @OkhanOkbay So I declare `date` in `class Workout: Object` as a primary key, or do I create a new variabel named `id`, and declare that as a primary key? – Camile Dec 08 '19 at 00:27
  • I understood you a little late and updated the comment – Okhan Okbay Dec 08 '19 at 00:28
  • If date is the recording date, then you can make it a primary key, yes. – Okhan Okbay Dec 08 '19 at 00:30
  • @OkhanOkbay The date is stored in this format; `2019-12-08 00:59:06 +0000;` – Camile Dec 08 '19 at 00:32
  • Store a string version of it and assign it as a primary key? – Okhan Okbay Dec 08 '19 at 00:34
  • checkout https://academy.realm.io/posts/realm-primary-keys-tutorial/ – Okhan Okbay Dec 08 '19 at 00:35
  • @OkhanOkbay Do I add a primary key for all the objects classes, or only the `Workout.swift` one? – Camile Dec 08 '19 at 00:36
  • Just Workout.swift, I believe – Okhan Okbay Dec 08 '19 at 00:37
  • @OkhanOkbay I tried to do it using primary keys, and save like: `realm.add(myWorkout, update: true)`, but it removes the exercise that I already has added, and update it with the new one. I want to keep both of the exercises in my workout. – Camile Dec 08 '19 at 12:45
  • That's the point here. Checkout this for details. https://realm.io/docs/swift/latest/#objects-with-primary-keys You can partially update the objects. If you can't, fetch workouts, append the new workout, then add that workout list to your existing object and update it with the new workout list – Okhan Okbay Dec 10 '19 at 22:45

2 Answers2

2

You want to:

  1. Fetch an existing Workout
  2. Create a new Exercise
  3. Append the Exercise to the Workout

I assume you know the primary key pkey of the Workout you want to fetch.

let myWorkout = realm.object(ofType: Workout.self, forPrimaryKey: pkey)! // 1: fetch an existing workout

let exercise = Exercise() // 2: create a new exercise with some sets
let set1 = Set(numReps: 1, weight: 1.0, aNote: "one")
let set2 = Set(numReps: 2, weight: 2.0, aNote: "two")
exercise.sets.append(objectsIn: [set1, set2])

try! realm.write {
    myWorkout.exercises.append(exercise) // 3: append
}
Kentaro Okuda
  • 1,557
  • 2
  • 12
  • 16
  • 1
    Great answer and generally speaking, it's usually good practice for Realm objects to have [Primary Keys](https://realm.io/docs/swift/latest/#primary-keys) to help differentiate one object from another. While you could use the 'date' property, which is there are two workouts on the same day? One point of clarification which may be obvious. Right after `let exercise = Exercise()` you can also create a set and add it to the sets property, then append the exercise to the workout - an empty exersise wouldn't contain any data and would have to then be loaded again to to update it with sets. – Jay Dec 08 '19 at 14:40
1

Since your users can only log in one workout per day, you can lookup that specific workout by date:

if let workout = realm.objects(Workout.self).filter("date = %@", date).first {
    // Workout found
    try! realm.write {
       workout.exercises.append(exerciseToAppend)
    }
} else {
   // Workout not found, handle it the way you want
}
rs7
  • 1,618
  • 1
  • 8
  • 16
  • Great answer assuming there is only one workout per day, what if you wanted more per day in the future? There would not be a simple way to differentiate one from the other. Primary key is way to go here. – Jay Dec 08 '19 at 14:41
  • @Jay There is only one workout per day, because workout is a "collection" of many exercises. So this app will never have more than one workout per day :) – Camile Dec 08 '19 at 16:10
  • @Camile Understood. In that case, this answer will give you the result you want. See my answer to your other question [Check if Realm data has been added on a specific date](https://stackoverflow.com/questions/59229239/check-if-realm-data-has-been-added-on-a-specific-date) for some other options if you ever want to expand on that. – Jay Dec 08 '19 at 16:15