How to Access Results from a Realm in Swift

How to access results from a realm in swift

You can retrieve specific SubscriptionClass by providing it's id which is used as primary key.

realm.object(ofType: SubscriptionClass.self, forPrimaryKey: id)

How to retrieve data from Realm's Results instance?

Results works like native Swift collections in many ways. If you are fetching a single object, you can just access it with Results.first let appleOn_05 = defaultRealm.objects(AchievementRecord.self).filter("dateID = '05-06-2017'").first

Subclasses of Object work like any other native class instance in Swift, so you can access their properties using the dot syntax.
let apple = appleOn_05.apple

Combining the two:

if let appleOn_05 = defaultRealm.objects(AchievementRecord.self).filter("dateID = '05-06-2017'").first {
let apple = appleOn_05.apple
}

Limit objects in Realm Results by condition in order to observe result

I going to attempt an answer but it may be off base.

The objective is to have a single realm result that can be observed for changes and also know what the newest delivery is.

Here's the code

self.packageResults = realm.objects(Package.self).sorted(byKeyPath: "delivered", ascending: false)

Then observe self.packageResults.

Whenever there's a change the observe closure will fire and deliver the results, sorted descending so the most current delivery will be 'at the top' i.e. index 0.

EDIT

Based on a comment and update to the question there was a question whether this answer provides a solution. Now there is a bit more data, just a slight modification produces the desired result (almost, keep reading)

self.packageResults = realm.objects(Package.self)
.filter("deliveryDate => 20190303")
.sorted(byKeyPath: "state", ascending: false)

then add an observer to self.packageResults. (note that I am using an Int for the timestamp to keep it simple)

To test, we use the data provided in the question with our observer code. The code prints the initial state of the data, and then prints the state after any delete, insert or modify.

func doObserve() {
self.notificationToken = self.packageResults!.observe { (changes: RealmCollectionChange) in
switch changes {
case .initial:
print("initial load complete")
if let results = self.packageResults {
for p in results {
print(p.deliveryDate, p.state.rawValue)
}
}
break
case .update(_, let deletions, let insertions, let modifications):
if let results = self.packageResults {
for p in results {
print(p.deliveryDate, p.state.rawValue)
}
}

then we run the code and add the observer. This is the output

initial load complete
20190303 1
20190304 0
20190305 0
20190306 0

if we then change the package 20190304 to 'delivered' we get the following output

20190303 1
20190304 1
20190305 0
20190306 0

So we are getting the desired result. HOWEVER, according to the question, the conditions of the query change as the next query would be for dates 20190304 and after.

If the conditions of the output change, the conditions of the query would have to change as well. In this case the desired result is to display the most currently delivered package each day, so the query would need to be updated each day to reflect that date.

As a possible solution, change the Package object to include a watched property

class Package: Object {
@objc enum State: Int {
case scheduled
case delivered
}
@objc dynamic var state = State.scheduled
@objc dynamic var deliveryDate = 0
@objc dynamic var watched = false
}

and update the query to only observe packages being watched, ignore ones not being watched (where watched = false)

self.packageResults = realm.objects(Package.self)
.filter("deliveryDate => 20190303 and watched == true")
.sorted(byKeyPath: "state", ascending: false)

Then, when you no longer need to know about an object, set it's watched property to false, and it will not be included in the results. Using the same process as above with this query, when changing 20190304 to delivered, we also change 20190303 watched property to false and the results are

 handle item delete, insert or mod
20190304 1
20190305 0
20190306 0

which appears to answer the question.

Sort realm results using a property of an element in a list

The objective is to sort patients by the latest date of a record in their in their list of records.

It can be done and there are several approaches. One option is, as patients records are being populated, to keep a separate property of the record with the latest date.

The patient object would look something like this

class Patient: Object, ObjectKeyIdentifiable {
@Persisted(primaryKey: true) var _id: ObjectId
@Persisted private var records: List<Record>
@Persisted var lastRecord: Record!

func addRecord(withRecod: Record) {
self.records.append(withRecord)
let recordArray = Array(self.records)

if withRecod != nil {
let sortedRecords = recordArray.sorted { $0.date < $1.date }
let lastRecord = sortedRecords.last!
let rec = Record(value: lastRecord)
self.lastRecord = rec
}
}
}

We added a function to populate the records list and made that list private so you are forced to use the addRecord function to populate the property.

The Array is needed as Realm doesn't sort in memory - so if the object is not yet persisted the records cannot be sorted, so an array is leveraged for that task.

Lastly, the array is sorted by date and then we make a COPY of the last record to store in the lastRecord property. Embedded objects are never persisted 'on their own' they can't be referenced in the same way other objects can, so a copy makes it work.

Then the sorting becomes easy

let patients = realm.objects(Patient.self).sorted(byKeyPath: "lastRecord.date")

Keeping in mind a updateRecord and a deleteRecord function may be in order to re-calculate the lastRecord upon those changes.

Realm Swift Results get object at index

Use standard indexing syntax to retrieve the value:

let task = tasks![1]

Since tasks is an optional, it could be nil. A safer way to write this would be to use optional binding with optional chaining:

if let task = tasks?[1] {
// use task
}

Reaching Realm Results object from different thread gives crash

Realm objects can only be used from the same thread that they were fetched.

So you have 2 main options, if you are going to use any of your data to populate UI, you'll have to fetch the objects in the main thread.

The other option is to create a new Realm instance and fetch the results again in the main thread, creating a Realm is supposed to be really lightweight.

You can also pass objects between threads but that is more complicated.

Filtering results from Realm

You can do this way:

Realm is not setup in my project so i am doing with struct.

Struct of Location:

struct Locations {

let latitude: Double
let longitude: Double
}

// Your Realm result Array
var theLocations = [Locations]()

// Adding Dummy Data into theLocations Array
theLocations.append(Locations(latitude: 37.33454847, longitude: -122.03611286))
theLocations.append(Locations(latitude: 37.33454218, longitude: -122.03638578))

// latitude and longitude to store values
var arrLat = [Double]()
var arrLong = [Double]()

// Looping through theLocations Array and Seperate latitude and longitude to append to array
theLocations.forEach{ location in
arrLat.append(location.latitude)
arrLong.append(location.longitude)
}

Hope this will help you.



Related Topics



Leave a reply



Submit