I am stuck in a problem. Let's assume I have this Realm Model:
class Table: Object {
dynamic var id = 0
dynamic var x: Int = 0
dynamic var y: Int = 0
dynamic var width:Int = 0
dynamic var height: Int = 0
dynamic var text: String = ""
dynamic var color: String = ""
dynamic var type: String = ""
let food = List<Food>()
override static func primaryKey() -> String {
return "id"
}
}
class Food : Object {
dynamic var id: Int = 0
dynamic var name = ""
dynamic var ingredients: String = "" // bigger text field
dynamic var size: Int = 0 // none, small, medium, big size
dynamic var price: Float = 0.0
dynamic var category: Category?
let additionalIngredients = List<Ingredient>()
override static func primaryKey() -> String {
return "id"
}
}
Let's say I have one table and added 2 times the same food on that table like so :
try! realm.write(){
table.food.append(food) // A
table.food.append(food) // B
realm.add(table, update: true)
}
If I change the additionalIngredients for food A , also at the same food B changes its values. I am doing that changes with this transaction :
try! realm.write(){
table.food.first!.additionalIngredients.removeAll()
for ingredient in ingredientsToAdd{
table.food.first!.additionalIngredients.append(ingredient)
}
realm.add(table, update: true)
}
I guess I am doing something wrong regarding the reference/instance, can someone give me a hint?
Thanks in advance!
List.append() adds the object itself to the list and not a copy of the object, so you only have one Food object.
Related
I have grouped data according to date and append values to AppointmentDateModel - tableValues.
As data contain of one same date with multiple appointments data so I grouped them.
But when I append values it automatically sorted or rearrange order by itself.
How can I set order as it is in the dictionary so the order cannot be changed? Or am I grouping them in a right way?
My main models are DownloadEntity and appointmentDownloadModel and then for grouped I use AppointmentDateModel
declaration:
var mDownloadEntity: [DownloadEntity] = []
var tableValues:[AppointmentDateModel] = []
var dict : [Int64:[AppointmentDownloadModel]] = [:]
Appending Code:
mDownloadEntity.forEach { apDate in
print(apDate)
var value = dict[apDate.appdate]
if(value == nil){
dict.updateValue([apDate.appointmentDownloadModel!], forKey: apDate.appdate)
}else{
value?.append(apDate.appointmentDownloadModel!)
dict.updateValue(value!, forKey: apDate.appdate)
}
}
dict.forEach{map in
let appointmentDateModel = AppointmentDateModel(appointmentDate: map.key, entities:map.value)
tableValues.append(appointmentDateModel)
}
Models:
struct AppointmentDownloadModel: Codable{
var appointmentModel: Appointment
var progress: Int = 0
var failedList: [Int: String] = [:]
var isFinished: Bool = false
}
struct DownloadEntity: Codable {
let id: Int
var appdate: Int64
var userId: Int
var dFirmId: Int
var appointmentId: Int
var appointmentDownloadModel: AppointmentDownloadModel?
}
struct AppointmentDateModel: Codable {
let appointmentDate:Int64
var entities:[AppointmentDownloadModel]
}
I am a beginner on programming and especially on iOS development
currently I am trying to use realm as the local database in an ecommerce app. I have Product and WishList object of Realm like below
The product:
class Product : Object {
#objc dynamic var productID : Int = 0
#objc dynamic var name : String = ""
#objc dynamic var categoryID : Int = 0
#objc dynamic var categoryName : String = ""
#objc dynamic var unitPrice: Double = 0.0
#objc dynamic var quantityInCart = 0
#objc dynamic var quantityFromServer = 0
#objc dynamic var descriptionProduct : String = ""
#objc dynamic var hasBeenAddedToWishList : Bool = false
#objc dynamic var hasBeenAddedToCart : Bool = false
#objc dynamic var isNewProduct : Bool = false
#objc dynamic var productWeight : String = ""
#objc dynamic var weightUnit : String = ""
#objc dynamic var minimumOrderQuantity = 0
#objc dynamic var maximumOrderQuantity = 0
override static func primaryKey() -> String? {
return "productID"
}
}
the Wishlist:
class WishList : Object {
var products = List<Product>()
}
my app can change the user. so let say if User A put some products on the wishlist (populates the WishList object with the product), after that he performs Log Out,
then it will make the User B's wishlist object will already have object after User B login.
so I think I need to insert userID both on Product and Wishlist object, and I have to also remove the primary key on Product object.
override static func primaryKey() -> String? {
return "productID"
}
so when I perform query or filter from realm database I can filter based on productID and also userID.
do I have the correct approach using way like that ? or is there a better approach? because to I am not comfortable having userID as the property of Product object like code below:
class Product : Object {
#objc dynamic var userID : Int = 0 <--- like this
#objc dynamic var productID : Int = 0
#objc dynamic var name : String = ""
#objc dynamic var categoryID : Int = 0
#objc dynamic var categoryName : String = ""
#objc dynamic var unitPrice: Double = 0.0
#objc dynamic var quantityInCart = 0
#objc dynamic var quantityFromServer = 0
#objc dynamic var descriptionProduct : String = ""
}
class WishList : Object {
#objc dynamic var userID : Int = 0 <--- and like this
var products = List<Product>()
}
and with this approach, I will also have 'duplicate' Product data on Product object with the same productID, but the userID on the property of the Product is different
You shouldn't add userID to either the Product or the Wishlist. A Product should be independent of specific users, so it should have no relationship to a user. On the other hand, a Wishlist is specific to a user, but instead of manually having to query the userID property of a specific Wishlist, you should take advantage of Realm's built-in relationships and declare a one-to-one relationship between a User and a Wishlist (you can either declare the relationship on WishList or on User, both work just fine).
So your Product definition should be left unchanged with its primaryKey being intact as well. Your Wishlist should look like the following:
class WishList : Object {
#objc dynamic var user: User?
let products = List<Product>()
}
Or if you want to access the WishList of a specific User from the user, you can modify your User like so:
class User: Object {
#objc dynamic var wishList: WishList?
...
}
I'm making an app for airports and I'm getting an array of data from one api, like so:
"data":[
{"id":"001","code":"ABZ","name":"Aberdeen","country":"United Kingdom"},
{"id":"002","code":"AUH","name":"Abu Dhabi","country":"United Arab Emirates"},
.
.
.
]
AND :
"airports":[
{"from":"001",
"to":["1","3","11","13","12","20","23","27","29","31","33"]
},
.
.
.
]
I have created realm model classes:
class AirportsDataRealm: Object {
#objc dynamic var name: String = ""
#objc dynamic var id: Int = 0
#objc dynamic var code: String = ""
#objc dynamic var country: String = ""
override static func primaryKey() -> String? {
return "id"
}
}
class AirportsFromToRealm: Object {
#objc dynamic var fromID: Int = 0
var toID = List<Int>()
override static func primaryKey() -> String? {
return "fromID"
}
}
now I want to save it into realm, I'm using swiftyJSON and I have used for-loop to do it and it is working fine but I think it's taking long time since the array is very long, here is what I've done:
// Airports Data
let countData = json["data"].count
for i in 0...countData - 1{
let airportsDataModel = AirportsDataRealm()
airportsDataModel.code = json["data"][i]["code"].stringValue
airportsDataModel.name = json["data"][i]["name"].stringValue
airportsDataModel.country = json["data"][i]["country"].stringValue
airportsDataModel.id = Int(json["data"][i]["id"].stringValue)!
try! realm.write {
realm.add(airportsDataModel, update: true)
}
}
//Airports FROM-TO
let countFromTo = json["airports"].count
for i in 0...countFromTo - 1{
let fromToDataModel = AirportsFromToRealm()
fromToDataModel.fromID = Int(json["airports"][i]["from"].stringValue)!
let arrayTo = json["airports"][i]["to"].arrayValue.map{ $0.intValue }
fromToDataModel.toID.append(objectsIn: arrayTo)
try! realm.write {
realm.add(fromToDataModel, update: true)
}
}
is there any way to save the whole array in realm in one shot without for-loop?
P.S
"there should be a relation between the two tables because each from 'id' has a list of 'to' id's and the id's are from the data table, for now I managed to create this relations when fetching the data using filters ,, so just ignore this"
Thank you
Simply use map method,
First I needed to add initializers to my object classes and pass json array as a parameter, like so:
class AirportsDataRealm: Object {
#objc dynamic var name: String = ""
#objc dynamic var id: Int = 0
#objc dynamic var code: String = ""
#objc dynamic var country: String = ""
convenience required init(withJSON json : JSON) {
self.init()
self.name = json["name"].stringValue
self.id = json["id"].intValue
self.code = json["code"].stringValue
self.country = json["country"].stringValue
}
override static func primaryKey() -> String? {
return "id"
}
}
class AirportsFromToRealm: Object {
#objc dynamic var fromID: Int = 0
var toID = List<Int>()
convenience required init(withJSON json : JSON) {
self.init()
self.fromID = json["from"].intValue
let toArray = json["to"].arrayValue.map{ $0.intValue }
self.toID.append(objectsIn: toArray)
}
override static func primaryKey() -> String? {
return "fromID"
}
}
Then by using map method the code will look like this:
func updateAirport(json: JSON) {
// Airports Data
let airportsData : [AirportsDataRealm]
let airportsDataJsonArray = json["data"].array
airportsData = airportsDataJsonArray!.map{AirportsDataRealm(withJSON: $0)}
//Airports FROM-TO
let airportsFromTo : [AirportsFromToRealm]
let airportsFromToJsonArray = json["airports"].array
airportsFromTo = airportsFromToJsonArray!.map{AirportsFromToRealm(withJSON: $0)}
//Write To Realm
try! realm.write {
realm.add(airportsData, update: true)
realm.add(airportsFromTo, update: true)
}
}
No for loops anymore ^_^
I have a database of tables Subject, Grade, Chapter and Question. A Subject has many Grade, a Grade and many Chapter, a Chapter has many Question. If I want to perform search all the questions of Subject = Biology, Grade = 4, Chapter = 1, how should I build the query?
My Classes
class Subject:Object {
dynamic var subject_id = 0
dynamic var subject_name = ""
let grades = List<Grade>()
override static func primaryKey() -> String? {
return "subject_id"
}
}
class Grade:Object {
dynamic var grade_id = 0
dynamic var grade_num = 0
let chapters = List<Chapter>()
override static func primaryKey() -> String? {
return "grade_id"
}
}
class Chapter:Object {
dynamic var chapter_id = 0
dynamic var chapter_num = 0
let questions = List<Question>()
override static func primaryKey() -> String? {
return "chapter_id"
}
}
class Question:Object {
dynamic var question_id = 0
dynamic var question_desc = ""
dynamic var question_ans = ""
override static func primaryKey() -> String? {
return "question_id"
}
}
So far the only way that I can think of to achieve this is as follows, which I feel that there are way to many nested loops and if else.
let realm = try! Realm()
let subjects = realm.objects(Subject).filter(NSPredicate(format: "subject_name = %#", "Biology"))
var searched:List<Question>?
for subject in subjects {
if subject.subject_name == "Biology" {
for grade in subject.grades {
if grade.grade_num == 4 {
for chapter in grade.chapters {
if chapter.chapter_num == 1 {
searched = chapter.questions
}
}
}
}
}
}
After Realm 0.100 it's possible to use inverse relationships in queries.
So, my suggestion would be to add inverse relationships to your model like this :
class Grade:Object {
dynamic var grade_id = 0
dynamic var grade_num = 0
let chapters = List<Chapter>()
let subjects = LinkingObjects(fromType: Subject.self, property: "grades")
override static func primaryKey() -> String? {
return "grade_id"
}
}
class Chapter:Object {
dynamic var subject_id = 0
dynamic var chapter_num = 0
let questions = List<Question>()
let grades = LinkingObjects(fromType: Grade.self, property: "chapters")
override static func primaryKey() -> String? {
return "subject_id"
}
}
class Question:Object {
dynamic var question_id = 0
dynamic var question_desc = ""
dynamic var question_ans = ""
let chapters = LinkingObjects(fromType: Chapter.self, property: "questions")
override static func primaryKey() -> String? {
return "question_id"
}
}
Then you can query your model similar to this:
let questionsIWant = realm.objects(Question.self)
.filter("ANY chapters.chapter_num == 3")
.filter("ANY chapters.grades.grade_num == 1")
.filter("ANY chapters.grades.subjects.subject_name == 'Biology'")
I've got an Article and a Category model linked by a many-to-one relationship. However, the Category model has a unique constraint on the id property because it's the primary key as you can see below.
class Article: Object
{
dynamic var id: String = ""
dynamic var title: String = ""
dynamic var category: Category()
override static func primaryKey() -> String? {
return "id"
}
}
class Category: Object
{
dynamic var id: String = ""
dynamic var title: String = ""
override static func primaryKey() -> String? {
return "id"
}
}
This will work until an Article got the same Category and throw an exception because of the unique constraint.
How am I supposed to implement this kind of relationship ? Is there any built-in way to persist only the Category id and retrieve the corresponding Category ?
Thanks
As you can read in Realm doc (0.92.1), you have to use a List<Object> for a many-to-one relationship.
See this link :
http://realm.io/docs/swift/latest/
class Dog: Object {
dynamic var name = ""
dynamic var owner: Person? // Can be optional
}
class Person: Object {
... // other property declarations
let dogs = List<Dog>()
}
let someDogs = Realm().objects(Dog).filter("name contains 'Fido'")
jim.dogs.extend(someDogs)
jim.dogs.append(rex)
So in your case, I guess it should be something like that :
class Article: Object
{
dynamic var id: String = ""
dynamic var title: String = ""
override static func primaryKey() -> String? {
return "id"
}
}
class Category: Object
{
dynamic var id: String = ""
dynamic var title: String = ""
dynamic var articles = List<Article>()
override static func primaryKey() -> String? {
return "id"
}
}
If your Realm version is older :
class Category: Object
{
...
dynamic var categories = RLMArray(objectClassName: Article.className())
}