How to create model like firebase structure using RealmSwift in iOS swift? - ios

I have been trying to create model like firebase database structure. I can able to create normal string, bool and int value but not able to do array and dictionary.
Here is my firebase structure screenshot:
Here i am trying to add groupMembers and to in model like firebase structure.
Here is my Model i tried to create with array and dictionary:
import Foundation
import RealmSwift
class RealmMessages: Object {
#objc dynamic var messageText : String?
#objc dynamic var sender: String?
let chatCreatedDateTimee = List<timeStampValue>()
#objc dynamic var chatId: String?
#objc dynamic var from: String?
#objc dynamic var groupMemberss : [String: String]!
let groupMemebersCount = RealmOptional<Int>()
#objc dynamic var task: Bool = false
#objc dynamic var to: Array = [String]()
}
class timeStampValue: Object {
let timestamp = RealmOptional<Int>()
}
Here is my contoller code: Trying to add value into realm database.
var dic : [String : String] = [:]
var cont = ["one", "two", "three"]
var oneVal = ["909090": "SELF", "808080": "Other"]
override func viewDidLoad() {
super.viewDidLoad()
let realm = try! Realm()
print("realm location:::\(String(describing: Realm.Configuration.defaultConfiguration.fileURL))")
let myMessage = RealmMessages()
myMessage.messageText = "Diva"
myMessage.sender = "yIvq1mQxjfZpjs1ybRTTlDOmUKV2"
let timevalue = timeStampValue()
timevalue.timestamp.value = 123123131
myMessage.chatId = "+918000080000"
myMessage.from = "+918000080000"
myMessage.groupMemberss = oneVal
myMessage.to = cont
try! realm.write {
realm.add(myMessage)
}
}
How to get groupMemberss and to structure in realm database like firebase. And how to create array and dictionary in realm

There are a number of solutions but here's two.
Assuming the data has been read in and the data from the groupMembers snapshot is sitting in a dictionary var that looks like this
let groupMembersDict = [
"919": "participant",
"111": "observer",
"222": "participant"
]
To store that in Realm, you can work with primitives and store each key and value in a separate List (think: Array) or you can leverage a managed Realm object and store those in a List.
If you want to keep the data within an object; here's what it would look like.
class GroupData: Object {
#objc dynamic var num = ""
#objc dynamic var type = ""
convenience init(withNum: String, andType: String) {
self.init()
self.num = withNum
self.type = andType
}
}
Here's the main object showing both options; either option 1: store the key value pairs in two arrays, or option 2: use the above GroupData object to store the key value pairs together
class Messages: Object {
#objc dynamic var messageText = ""
//option 1: two lists of primative strings that can be accessed like an array.
// downside is managing two lists
let groupNum = List<String>()
let groupType = List<String>()
//option 2: a list of members using another Realm object
let groupNumType = List<GroupData>()
}
And some code to create two messages, one of each type
let msg0 = Messages()
msg0.messageText = "My message"
for member in groupMembersDict {
msg0.groupNum.append( member.key )
msg0.groupType.append( member.value )
}
let msg1 = Messages()
msg1.messageText = "This message"
for member in groupMembersDict {
let aGroup = GroupData(withNum: member.key, andType: member.value)
msg1.groupNumType.append(aGroup)
}
store them in realm
realm.add(msg0)
realm.add(msg1)
read them both in an display the message from option 2. Option 1 would be just iterating over the arrays to print the group data
let messageResults = realm.objects(Messages.self)
for msg in messageResults {
print(msg.messageText)
for group in msg.groupNumType {
print(group.num, group.type)
}
}
Keep in mind that all managed properties must be primitives: NSString, NSDate, NSData, NSNumber or List, Results, RLMLinkingObjects, or subclasses of RLMObject like the GroupData shown above.

Related

How to store Array of Dictionaries to Realm Database in Swift

I am getting JSON data from server by api call in swift application.
So, I want to store that into Realm data base and again need to fetch to show in tableview.
I have no idea about Realm database, After, checked few forums, I got basic idea for creating Object class.
So, I have installed Realm pod file and imported that library to my classes.
My JSON data is
[{
"type": "story",
"story": 
{
"author-name": "",
"headline": "Quotes ",
"summary": "Best quotes of Muhammad Ali",
"hero-image": "https://image”
}
},
{
"type": “Trending”,
"story": 
{
"author-name": "",
"headline": "Quotes ",
"summary": "Best quotes of Muhammad Ali",
"hero-image": "https://image”
}
},
{
"type": “Technology”,
"story": 
{
"author-name": "",
"headline": "Quotes ",
"summary": "Best quotes of Muhammad Ali",
"hero-image": "https://image”
}
},
{
"type": “Top”,
"story": 
{
"author-name": "",
"headline": "Quotes ",
"summary": "Best quotes of Muhammad Ali",
"hero-image": "https://image”
}
}
]
And I have each type keyword has different model class saved data from api data to show in Tableview
like
let storyObj = StoryModule()
let trending = StoryModule()
let technology = StoryModule()
let stotopryObj1 = StoryModule()
and I am saving each key value for every type
if abc.type == "story" {
let storyObj = abc.story
storyObj.authorname = storyObj?.authorname
storyObj.heroimage = storyObj?.heroimage
storyObj.headline = storyObj?.headline
storyObj.summary = storyObj?.summary
self.treningStoriesList.append(storyObj)
}
It is same for remaining Trending, Top and Technology objects.
and the Realm module is
import RealmSwift
class DemoInfo: Object {
#objc dynamic var category = ""
let items = List<DemoList>()
}
class DemoList : Object {
#objc dynamic var authorName = ""
#objc dynamic var imageUrl = ""
#objc dynamic var summary = ""
#objc dynamic var headLine = ""
}
And In MainViewController class,
let realmDB = try! Realm()
But, Here I got struck, How to save those storyObj,technology,top, etc module data and fetch.
Can anyone suggest me?
If you want to add a realm object in your db, you must define a primary key for each realm object classes. So, you need to change your JSON file, after you can create your realm objects like this;
DemoObject.swift
import RealmSwift
class DemoObject: Object {
#objc dynamic var id: String = ""
#objc dynamic var type: String = ""
#objc dynamic var subObject: SubObject?
override static func primaryKey() -> String? {
return "id"
}
}
SubObject.swift
import RealmSwift
class SubObject: Object {
#objc dynamic var id: String = ""
#objc dynamic var authorName: String = ""
#objc dynamic var imageUrl: String = ""
#objc dynamic var summary: String = ""
#objc dynamic var headLine: String = ""
override static func primaryKey() -> String? {
return "id"
}
}
Then, you can use these codes to add your db.
let realm = try! Realm()
let demo = DemoObject()
demo.id = "1"
let sub = SubObject()
sub.id = "1"
sub.authorName = "Author Name"
sub.headLine = "Head Line"
sub.summary = "image Url"
demo.subObject = sub
try! realm.write {
realm.add(demo, update: true)
}

How to save array into Object in Realm Database

I'm trying to save an array data(from CarteData object) into CustomerData object in realm but I got the error from the line of append data to Object. I'm just new with Swift, please tell me the right way of storing data array to object. Thanks so much.
let carte = CarteData()
carte.carteID = record.value(forKey: "carteID") as! String
carte.carteMemo = record.value(forKey: "carteMemo") as! String
newCustomer.cartes.append(carte)
Error crash message:
My CustomerData Object:
class CustomerData: Object {
#objc dynamic var cusName: String = ""
#objc dynamic var cusID: String = ""
#objc dynamic var cusMail: Int = 0
#objc dynamic var cusBirth: Date?
let cartes = List<CarteData>()
}
My CarteData Object:
class CarteData: Object {
#objc dynamic var carteID: String = ""
#objc dynamic var carteMemo: String = ""
var parentCategory = LinkingObjects(fromType: CustomerData.self, property: "cartes")
}

Not need to update object in Realm

I try to read json and create Realm, so my code:
func workWithFileJSON () {
//local file JSON
let file = Bundle.main.path(forResource: "MobileDbSchema", ofType: "json")!
let url = URL(fileURLWithPath: file)
let jsonData = NSData(contentsOf: url)!
//Parce JSON
let json = try! JSONSerialization.jsonObject(with: jsonData as Data, options: [])
try! realm.write {
//Create data from JSON to our objects
realm.create(DataRoot.self, value: json, update: true)
}
}
and file with classes:
import Foundation
import RealmSwift
class DataRoot: Object {
dynamic var id = 0
dynamic var name = ""
let transport_type = List<Transport_type>()
override class func primaryKey() -> String? {
return "id"
}
}
class Transport_type: Object {
dynamic var id = 0
dynamic var name = ""
let routes = List<Routes>()
override class func primaryKey() -> String? {
return "id"
}
}
class Routes: Object {
dynamic var id = 0
dynamic var name = ""
let directions = List<Directions>()
override class func primaryKey() -> String? {
return "id"
}
}
class Directions: Object {
dynamic var id = 0
dynamic var name = ""
dynamic var dayIdFrom = 0
dynamic var dayIdTo = 0
let stops = List<Stops>()
override class func primaryKey() -> String? {
return "id"
}
}
class Stops: Object {
dynamic var id = 0
dynamic var busStop: BusStop?
let timetable = List<Timetable>()
override class func primaryKey() -> String? {
return "id"
}
}
class BusStop: Object {
dynamic var id = 0
dynamic var name = ""
dynamic var descript = ""
override class func primaryKey() -> String? {
return "id"
}
}
class Timetable: Object {
dynamic var hour = 0
dynamic var minute = 0
dynamic var group_index = 0
dynamic var notes = ""
}
after my first run I see good data in Realm:
but after second run I see data in Timetable x 2 and etc. time after each run.
In Timetable there are no primary keys (here don't need it). Why after each update (run) I see increase data in Timetable and how to resolve my mistake?
Even if your app doesn't need primary keys, Realm.add(_:update:) requires your Object class to implement one so it is able to identify pre-existing entries as opposed to new ones. If you do not specify a primary key, even if update: is set to true, it will add each item from JSON as a new object.
Ideally, you should be able to implement some kind of primary ID for each entry in the JSON feed so you can simply pass that along to Realm.
However, if you cannot implement primary keys, but you know that every new JSON object you pull down is a complete snapshot of your timetables, then you could also simply consider deleting all of the pre-existing timetable objects in your Realm file before adding the latest ones from the JSON file.

Realm.objects() returns empty objects

My class has all properties as dynamic but still when retrieving them from realm i get a collection of empty objects, and check the realm db with the realm browser and the data is there, this is my class:
class ProjectEntity: Object {
/**
Property: All properties of the ProjectEntity
**/
dynamic var ProjectId = 0
dynamic var ProjectTitle = ""
dynamic var ProjectSubtitle = ""
dynamic var ProjectType = ""
dynamic var ProjectClass = ""
dynamic var ProjectCoordinates = ""
dynamic var ProjectGraphType = ""
dynamic var ProjectModifiedOn = NSDate(timeIntervalSince1970: 0)
dynamic var ProjectCity = ""
dynamic var ProjectCounty = ""
dynamic var ProjectZip = ""
override static func primaryKey() -> String? {
return "ProjectId"
}
func getShape() -> MapShape{
let adapter = ProjectsJSONAdapter()
let shape: MapShape = adapter.parseShape(id: self.ProjectId, type: self.ProjectGraphType, jsonStr: self.ProjectCoordinates)
return shape
}
}
here is how i'm reading the data:
let projectsList = realm.objects(ProjectEntity)
for project in projectsList {
projects.append(project)//The properties in project have all their default/empty values
}
any ideas?
How are you retrieving the persisted ProjectEntity objects? The following code snippet should do the trick:
let entities = Realm().objects(ProjectEntity)
first your class need to inherit RLMObject :
class ProjectEntity: RLMObject {
...
}
and after if you want all the ProjectEntity objects try this :
let allProjectEntityObjects: RLMResults = ProjectEntity.allObjects()
if you need some extra help you can follow this tutorial from Realm :
Building a To-Do App with Realm

Insert object in RLMArray property on already persisted object?

I have a fairly simple and straightforward issue I'm trying to solve with Realm. I have objects which have an array property on them (threads). When I fetch all the threads via our API, they're all persisted into Realm since the parent objects are individually saved and thus all child objects (messages & users) within the array property are properly persisted as well. But during the lifecycle of the app I need to add new messages into that array property. Here's what I'm attempting to do:
func addPubNubMessageToThread(notification: NSNotification) {
if let info = notification.userInfo as? Dictionary<String, AnyObject> {
var embeddedMessage = Message(json: (info["data"] as? NSDictionary)!)
let threadId = (info["thread"]! as String)
// Persist the message to Realm for future use
var respectiveThread = Thread(forPrimaryKey: threadId)
let realm = RLMRealm.defaultRealm()
realm.beginWriteTransaction()
respectiveThread.conversation.insertObject(embeddedMessage, atIndex: UInt(0)) // Always fails here in XCode with the error below
realm.addOrUpdateObject(respectiveThread)
realm.commitWriteTransaction()
}
}
But each time I get the following error:
*** Terminating app due to uncaught exception 'RLMException', reason: 'Setting unique property '_id' with existing value '540729b543dd5d1868a42b5d''
For more context, here are my Realm models:
class Message: RLMObject {
dynamic var _id = ""
dynamic var type = ""
dynamic var text = ""
dynamic var author = User()
dynamic var created = NSDate()
dynamic var lastUpdated = NSDate()
}
class Thread: RLMObject {
dynamic var _id = ""
dynamic var name = ""
dynamic var conversation = RLMArray(objectClassName: Message.className())
dynamic var participants = RLMArray(objectClassName: User.className())
dynamic var created = NSDate()
dynamic var lastUpdated = NSDate()
}
class User: RLMObject {
dynamic var _id = ""
dynamic var name = ""
dynamic var firstName = ""
dynamic var lastName = ""
dynamic var email = ""
dynamic var phone = ""
dynamic var username = ""
dynamic var avatar = NSData()
dynamic var created = NSDate()
dynamic var lastUpdated = NSDate()
}
Each message has a property called author, and the _id it's complaining about is the _id of the author (or user object) of the message. The error message is hard to decipher. I think it's saying that I'm trying to create a new user object with a primary key that already exists. If that's the issue, what should I do instead to add new Realm objects to an array property on an already persisted object?
Edit
I am setting the primary key for each model like so:
override class func primaryKey() -> String {
return "_id"
}
And _id is a GUID generated by MongoDB...so it's globally unique.
The problem is that when calling
insertObject
your object and all child objects are created in the Realm instead of updated if they already exist. If you first explicitly update your object (which applies to all child objects as well), then this should avoid the issue:
var persistedMessage = realm.addOrUpdateObject(embeddedMessage)
respectiveThread.conversation.insertObject(persistedMessage, atIndex: UInt(0))
Your problem is probably in your the Message(json:) initializer. When you process the JSON for the message, I'm guessing the author ID is passed (and perhaps the rest of the author data). In your initializer you are probably instantiating a new User, rather than getting an instance of the existing User in the Realm. I recreated your model objects, and then created an existing user, thread and message. I was able to deserialize a message from JSON and add the new message to the existing conversation array, as long as my deserialization logic grabbed an existing user if it was provided. Here is my example initializer:
init(json : NSDictionary) {
self._id = json["_id"] as String
self.type = json["type"] as? String ?? ""
self.text = json["text"] as? String ?? ""
self.created = json["created"] as? NSDate ?? NSDate()
self.lastUpdated = json["lastUpdated"] as? NSDate ?? NSDate()
if let author = json["author"] as? NSDictionary {
if let authorId = author["_id"] as? String {
self.author = User(forPrimaryKey: authorId)
}
}
super.init()
}
In this case, my example JSON:
{
"_id": "2",
"text": "new message",
"author": {"_id": "1"}
}
And finally, the code that reads the JSON and adds to an already saved thread:
var error: NSError?
var jsonDictionary : NSDictionary!
if let dictionary = NSJSONSerialization.JSONObjectWithData(jsonData, options: NSJSONReadingOptions.allZeros, error: &error) as? NSDictionary {
jsonDictionary = dictionary
} else {
NSLog("\(error)")
return
}
let realm = RLMRealm.defaultRealm()
realm.beginWriteTransaction()
let newMessage = Message(json: jsonDictionary)
self.thread.conversation.addObject(newMessage)
realm.addOrUpdateObject(self.thread)
realm.commitWriteTransaction()

Resources