Realm how to save item if not exist else it should update - ios

I have a data coming from webservice. I have same models made in my project. To demonstrate the model let me show a little idea of my model
Model1:
class Standard {
var Id = 0
var standardName = ""
var students : [StudentModel] = nil
}
Model2:
class StudentModel {
var Id = 0
var stdName = ""
var Teacher: [TeacherModel] = nil
}
Model3:
class TeacherModel {
var Id = 0
var Name = ""
}
Now what I am facing is as follow :
I have TeacherModel in DB already, but I dont have student model and standard model instance int he Realm, so it is supposed to save coming student and standard data in Realm. and skip or update TeacherModel in Realm. But right now it is crashing on TeachModel data as one Teacher with same things are already saved in Realm.SO i am looking forward to some sort of method in which it update or just skip saving Item if already exist in the Realm.
Note: These models are just to demonstrate my case, where as I know there are many typos and other thing. Also I did not showed any implementation of Realm over my Models. Its just to show you the things to make you understand.

Well you need to have class func primaryKey() -> String? overriden.
override class func primaryKey() -> String? {
return "Id"
}
And then use realm.write(...) or realm.create(...) functions with update parameter set to true.

Related

Realm Relation how to implement

I am working on iOS and that is saving product. and this product has some more things inside its model
let suppose the following model
#objcMembers public class ProductModel : Object, Codable {
dynamic var Id : Int = 0
dynamic var Name : String = 0
dynamic var Price : Double = 0.0
}
and the other model (CustomerModel) that contains the ProductModel is as follow
#objcMembers public class CustomerModel : Object, Codable {
dynamic var Id : Int = 0
dynamic var Name : String = 0
var Product : ProductModel? = nil
}
Now when I save customer with the product inside it, I can see that in Realm it gets saved successfully. But if and only if that object is not in Realm already,
Let suppose this
let customer1 = CustomerModel()
customer1.Id = ...
customer1.Name = .....
customer1.Product = product1
Now this customer data is saved. But I am getting exception if I try to save following data
let customer2 = CustomerModel()
customer2.Id = ...
customer2.Name = .....
customer2.Product = product1
Just notice that customer2 also want to save product info that is already saved in Realm namely "product1".
So how to handle this sitution.
I am trying to save the data with the following generic function for realm objects
func save <T: Object> (_ obj : T){
do {
try realmObj.write{
realm.add(obj)
}
}catch{}
}
Question 2:
Also I want to get All Customer, I know how to do it, but problem is It never retrieves the Product inside the Customer. I can see in Realm DB Browser that the customer that get saved with the product, that customer table contains the reference of Product also. But when I try to get all customer then that customer have only customer details not Product detail. Whereas that must be there.
Just put dynamic keyword before your property
dynamic var Product : ProductModel? = nil

Realm Swift iOS - Can't Set Primary Key

I'll try to explain my scenario as short as possible, I have read some comments on Realm GitHub Repo about this issue:
Terminating app due to uncaught exception 'RLMException', reason:
'Can't set primary key property 'id' to existing value 'xxxxxxx'.
Here's my issue:
I got two classes.
Appointment Model Class
import Foundation
import RealmSwift
class Appointment: Object {
dynamic var id = 0
dynamic var user_id: String?
dynamic var profile_id: String?
let mainMeeting = List<Meeting>()
let meetingsWithOtherInfo = List<Meeting>()
override static func primaryKey() -> String? {
return "id"
}
}
Meeting Model Class
import Foundation
import RealmSwift
class Meeting: Object {
dynamic var id = 0
dynamic var name: String?
dynamic var created_at: String?
// other info
dynamic var restaurant_venue: String?
override static func primaryKey() -> String? {
return "id"
}
}
I am fetching the Appointments from my server API like this
for fetchedAppointment in allAppointmentsFromAlamofire {
let existingAppointment: Results<(Appointment)>! = realm.objects(Appointment).filter("id = \(fetchedAppointment["id"]!)")
let newAppointment: Appointment = Appointment()
newAppointment.id = fetchedAppointment["id"]! as! Int
....
// add data to Meeting connected to Appointment
let newMeeting = Meeting()
newMeeting.id = fetchedAppointment["meetings"]["id"]! as! Int
...
// update or add new entry
try! realm.write {
print("NEW APPOINTMENT: \(newAppointment)")
realm.add(newAppointment, update: existingAppointment.count == 0 ? false : true)
}
}
The error comes out whenever the program is trying to update existing entry in realm - whenever the existingAppointment is 1. the workaround here, from what I've read from Github Realm is to delete the override static func primaryKey() in Meeting Class.
There is no issue if I am just adding new entries to Appointment, but again, the issue comes out if I will be updating, and the issue goes away if I remove the primaryKey() in Meeting Class ---- BUT, in other screens of my app, I really need to have that primaryKey() in Meeting Class.
My wild guess here is that every time that I need to update entries in Appointment, I should update too the Meeting.
So, the question is: why is this happening? Is my wild guess correct? Any other way to solve this?
It looks like you are trying to update the newAppointment object with a value that is not its primary key.
realm.add(newAppointment, update: existingAppointment.count == 0 ? false : true)
Instead, Realm is expecting you to provide the key for that object so that it can update the specified object.
It looks like you are setting the key value here, which is what you should use for your update.
let newAppointment: Appointment = Appointment()
newAppointment.id = fetchedAppointment["id"]! as! Int
Realm documentation on updating with keys.
You don't need to set the update argument of add(:_, update: _) to false if you provide a new object. If your model has a primary key and you want to create or update, you can pass true and Realm will automatically figure out whether an object with the same primary key is already managed in the database or not.

How to link two Realm objects

I'm new to iOS development and currently using Realm as database. My first tableview display Restaurant object and second table display customer objects. How can i link this two objects?. Means when i click each restaurant it will display different customer.
class Restaurant: Object {
dynamic var restname: String = ""
dynamic var date: String = ""
}
class Customer: Object {
dynamic var id = 0
dynamic var name: String = ""
dynamic var price: Float = 0.0
dynamic var drinks: Float = 0.0
override static func primaryKey() -> String? {
return "id"
}
}
You make references to your models like so
class Customer: Object {
dynamic var restaurant: Restaurant?
}
You also have the possibility to get reverse relationship with LinkingObjects(fromType:, property:)
You can write in your other model
class Restaurant: Object {
let customers = LinkingObjects(fromType: Customer.self, property: "restaurant")
}
That way you don't duplicate relationships.
If I understand, in Restaurant class put this:
dynamic var _customer = Optional(Customer())
or in Customer class put this line:
dynamic var _restaurant = Optional(Restaurant())
NOTE: Name of variable with lower dash, may be any name, my habit is to put lower dash

Realm iOS relationship from mysql json results

I want to use Realm to my iOS app but I have a problem with the relationship. What I want to achieve is a relationship between the following two RLMobjects :
class Catalogue: RLMObject {
dynamic var ID = ""
dynamic var greekName = ""
dynamic var deutschName = ""
dynamic var createdAt = NSDate()
dynamic var updatedAt = NSDate()
override class func primaryKey() -> String? {
return "ID"
}
}
class Products: RLMObject {
dynamic var foodName = ""
dynamic var foodDescription = ""
dynamic var foodPrice = ""
dynamic var createdAt = NSDate()
dynamic var updatedAt = NSDate()
dynamic var category: Catalogue?
}
I am retrieving all my data from a server in JSON format and the problem is that
I can not set the category as relationship to Catalogue ID.
In my database the category field is a foreign key to the Catalogue ID.
Does anyone knows how can I do that in Realm?
Thank you in advance.
Rather than storing the Catalogue ID in the dynamic var category: Catalogue? relationship field you will need to find the Catalogue object and just store that directly. This is how you link objects and is an important and powerful part of using NoSQL type DB's like Realm.
I would also add an array of products relationship on Catalogue so that you can link all the products to the Catalogue itself.
You can see more discussion about this here if that wasn't fully clear. Hope this helps

Trying to create a Swift Realm Data Model

I have looked at the Realm.io docs. I am working on an application to track my vehicle expenses. I have put together what I think might work for a data model in Realm, but I am new to it and not sure if this is something that will work or if there is a better way to do it. Here is what I have, and I have not put this in a project and tried to compile yet. The realm.io docs are a little vague to me, so maybe someone can tell me what you think. I have included some comments in places that I am just not sure how to achieve what I'm going for...
// Vehicle model
class Vehicle : RLMObject {
dynamic var name = “”
dynamic var number = “”
dynamic var currentMiles = 0
dynamic var entries = RLMArray(objectClassName: Entry.className())
}
// Entry model
class Entry: RLMObject {
dynamic var vehicle: Vehicle //??
dynamic var date = NSDate()
dynamic var expense = 0.0
dynamic var mileage : Vehicle.currentMiles // want to update the Vehicle mileage with each entry
}
// Gas model
class Gas: Entry {
dynamic var gallons = 0
dynamic var pricePerGallon = 0.0
}
// OilChange model
class OilChange : Entry {
dynamic var milesBetweenChanges = 0
}
// Other Service model
class OtherService: Entry {
dynamic var notes = “”
}
You're on the right track! The only model that needs work is Entry, I think. First, here's your model with my annotations:
// Entry model
class Entry: RLMObject {
dynamic var vehicle: Vehicle // This is valid Swift, but you'll need to set the value in the designated initializer (`init()`).
dynamic var date = NSDate()
dynamic var expense = 0.0
dynamic var mileage : Vehicle.currentMiles // This isn't valid Swift, since `Vehicle` is a class, and doesn't have a `currentMiles` member
}
What you want is something like this:
// Entry model
class Entry: RLMObject {
dynamic var vehicle = Vehicle() // Use a default value so that `init()` succeeds, but you can still use `init(vehicle: Vehicle)` in your code
dynamic var date = NSDate()
dynamic var expense = 0.0
dynamic var mileage = 0
init() {
// Must override init() when adding a convenience initializer
super.init()
}
convenience init(vehicle: Vehicle) {
super.init()
self.vehicle = vehicle
mileage = vehicle.currentMiles
}
}
It's unfortunate that you find Realm's docs vague. Please let us know if there's anything in particular you'd like us to clarify. We're a pretty approachable bunch!

Resources