Realm-cocoa: Add Query RLMArray / RLMResults by index range

Created on 6 Mar 2015  路  27Comments  路  Source: realm/realm-cocoa

Spurred from here https://groups.google.com/forum/#!topic/realm-cocoa/iMenONGdfXY

Blocked Pipeline-Idea-Backlog T-Enhancement

Most helpful comment

+1

Use Case: The fine grained notifications are wonderful. But when combined with a large Result where paging is a must (bound to collection view) it becomes a pain. For example I would like to show the first 10 items in my collection view and then only listen to changes (inserts updates deletes) to those ten items. Then if a user scrolls down, the next ten items are added to the collection view and we listen to changes to the first 20 items. I would also welcome any workarounds?

All 27 comments

Should also make RealmSwift's List and Results sliceable.

@bdash I believe your work on limit would actually accomplish most of this?

Can we expect this feature to be available soonish? :)

Can we expect this feature to be available soonish? :)

Unfortunately not.

Although we're actively discussing this functionality, and do intend to provide it eventually, no one is currently working on this and it is labelled as "P2", meaning it is prioritized after our "P1" issues.

Is there a recommended workaround for this?
I have a query returning ~20,000 items and it makes a lot of sense to process it in chunks. Without a slice I have to resort to 1 at a time instead of batch-at-a-time processing.

Is there a recommended workaround for this?

Nothing elegant, I'm afraid. If these objects use primary keys, and your "processing" doesn't delete any of them, you can perform KVC collection modifications on a subset of them, which would prevent creating the accessors for those objects.

Here's one way to operate on a large results in batches of a thousand objects without creating accessors for each object:

class Email: Object {
  dynamic var id = 0
  dynamic var read = false
  override static func primaryKey() -> String? { return "id" }
}

// Helpers
extension CollectionType {
    func chunk(withDistance distance: Index.Distance) -> AnySequence<SubSequence> {
        var index = startIndex
        return AnySequence(anyGenerator {
            defer { index = index.advancedBy(distance, limit: self.endIndex) }
            return index != self.endIndex ? self[index ..< index.advancedBy(distance, limit: self.endIndex)] : nil
        })
    }
}

// Code
let largeResults = realm.objects(Email).filter("read == false")
let largeResultsIDs = largeResults.valueForKey("id") as! [Int]
for subIDs in largeResultsIDs.chunk(withDistance: 1000) {
  try! realm.write { // error handling omitted for brevity
    realm.objects(Email).filter("id IN %@", Array(subIDs)).setValue(true, forKey: "read")
  }
}

Depending on the amount of data, it may be cheaper to create the accessors rather than re-query for primary keys. This also works for objects without primary keys:

// Models
class Email: Object {
  dynamic var read = false
}

// Code
let largeResults = realm.objects(Email).filter("read == false")
while !largeResults.isEmpty {
  try! realm.write { // error handling omitted for brevity
    (Array(largeResults.suffix(1000)) as NSArray).setValue(true, forKey: "read")
  }
}

+1 for this feature. I have a UITableView backed by a frequently updating RLMResults whose results I'd like to cap at 10 objects.

+1 for this feature.

+1 for this feature.

+1 for this feature.

+1

+1

+1

+1

+1

+1

Just started with Realm and not limit or offset? really?, and how about change listener when you only want a subset. This really sucks.

it would help if people looking for this behavior could share their use case, since there are only a select few situations in which this would be necessary, as far as we know. Since Realm lazily loads objects in Realm collections, there'd be no performance gain with a limit feature.

My situation is like this: I have a tableview backed by RLMArray, I want to load data lazily when user interacts, like every pull to load 10 more objects. So it will be convenient if I could query RLMArray by index range.

@Jowyer the existing lazy loading behavior does that though.

Here is an example of getting last three elements of RLMResults:

self.arrayOfSubscriptedResults = [NSMutableArray new];
RLMResults *results = [[ModelRO objectsWhere:@"smth == 21"] sortedResultsUsingProperty:@"property" ascending:NO];
[self.arrayOfSubscriptedResults addObject: [results lastObject]];
[self.arrayOfSubscriptedResults addObject: [results objectAtIndex:(results.count - 1)]];
[self.arrayOfSubscriptedResults addObject: [results objectAtIndex:(results.count - 2)]];

Another one solution here

+100500
Just migrated from CoreData and lack of this feature makes Realm unusable. OMG!

My use case:

I have a UICollectionView with 200,000+ items. However, unfortunately with bothreloadData on a full set and insertItems on batches results in UICollectionView locking up the UI. So, I need to limit the amount of items that the dataSource and UICollectionView see. Then as the user scrolls, I could "add"/"remove" items to/from the limited-Results of the master List.

With Realms's current abilities, keeping track of the offset and transforming the index for the dataSource requests isn't much harder. However, with the changeset notifications, it becomes a lot more cumbersome. In either case, it would be cleaner to just have a single source of truth for the data (Results) to give to these objects where the indexes are already correct, without needing to wrap index accessing in additional offset logic nor passing around more references to objects to facilitate it.

+1

+1

Use Case: The fine grained notifications are wonderful. But when combined with a large Result where paging is a must (bound to collection view) it becomes a pain. For example I would like to show the first 10 items in my collection view and then only listen to changes (inserts updates deletes) to those ten items. Then if a user scrolls down, the next ten items are added to the collection view and we listen to changes to the first 20 items. I would also welcome any workarounds?

+1

Use case: limiting the results by reading a predetermined number of objects from a query is not bounds safe. Our app crashes when the count of a query result changes while we are looping through it and reading objects.

Edit: I found mention of an exception in the docs, namely that for ... in comprehensions do not treat results as live, auto-updating data, which seems safer. The syntax is far less clean than functional swift operators like map, though.

What is the current state of this?

Really necessary feature thanks!

Was this page helpful?
0 / 5 - 0 ratings