The way how to currently fetch multiple objects by primary keys is
NSArray *primaryKeys = @[@"bar1", @"bar2", @"bar3"]
RLMResults *results = [RLMFoo objectsWhere:@"id IN %@", primaryKeys];
I belive this can be done much more efficient, than using a predicate with IN... this is especially important, if you imported multiple objects in background thread and need to fetch them in main thread
Having a dedicated method like this would open future ways of improving this important query
[RLMFoo objectsWithPrimaryKeys:@[@"bar1", @"bar2", @"bar3"]]
Interesting, I do this quite a bit for the reason you mentioned: Importing on background threads and then listing on main thread. Just curious, what makes you think an IN query is not efficient? I have nothing to backup whether it is or isn't, I'm just curious what sparked this issue.
Ok, it's just my assumption, that the underlaying architecture could do a far performant fetch, than using a generic predicate... at least adding this method to the framework, would provide a convenience method and later base for possible optimalizoation
There's nothing special about primary keys that makes looking them up more efficient than querying on any other indexed column. objectForPrimaryKey: is slightly more efficient than the corresponding query because it skips the work of building a query from the NSPredicate and can take advantage of the fact that there's only zero or one matching objects. The latter doesn't apply to looking up multiple objects, and the former gets relatively less significant as you add more items to the IN clause.
but there would be still a performance gain as the predicate wouldn't be needed build and the results count would be determined with the input count ([result count] <= [keys count])... i mean Realm suppose to be most performant as possible...
and also from the architecture point of view and the convenience point of view, it makes sense to have objectsForPrimaryKeys
I'm not sure if this is at all interesting but take a look... For reference:
createOrUpdate uses realm.create(T.self, value: object, update: true)
reference uses realm.objectForPrimaryKey(T.self, key: objectID)
list uses realm.objects(T.self).filter("id IN %@", objectIDs)

So even doing the IN query with 1,000 ids is really really fast. Regardless I completely agree that the function objectsForPrimaryKeys is a nice piece of API to have.
Sorry for the delay in getting back to you, the whole Realm team was away on a mini internal Realm conference all of last week...
My initial reaction is that you can easily accomplish objectsForPrimaryKeys functionality by composing existing APIs (either objectForPrimaryKey/flatMap or objects/filter depending on what you want).
Regardless, I'll still bring up the possibility of adding this to our official API with the team later this week.
In the meantime, if you'd like to add this to Realm yourself, just add the following extension:
extension Realm {
func objectsForPrimaryKeys<T: Object, K: AnyObject>(type: T.Type, keys: [K]) -> Results<T> {
return objects(type).filter("\(type.primaryKey) IN %@", keys)
}
// or
func objectsForPrimaryKeys<T: Object, K: AnyObject>(type: T.Type, keys: [K]) -> [T] {
return keys.flatMap { self.objects(type, key: $0) }
}
}
Which approach is more efficient will likely vary based on the number of objects involved.
Alright, I brought this up with the team and our consensus is unchanged, that objectsForPrimaryKeys: is unnecessary since the current approaches are more efficient and a dedicated method would just add more heft to the API.
Hi @jpsim thanks for your code snippet
This one is throwing an error though:
func objectsForPrimaryKeys<T: Object, K: AnyObject>(type: T.Type, keys: [K]) -> [T] {
return keys.flatMap { self.objects(type, key: $0) }
}
Extra argument 'key' in call
Any idea how to fix it? I don't see any definitions of self.objects that takes a key... thanks!
Most helpful comment
Sorry for the delay in getting back to you, the whole Realm team was away on a mini internal Realm conference all of last week...
My initial reaction is that you can easily accomplish
objectsForPrimaryKeysfunctionality by composing existing APIs (eitherobjectForPrimaryKey/flatMaporobjects/filterdepending on what you want).Regardless, I'll still bring up the possibility of adding this to our official API with the team later this week.
In the meantime, if you'd like to add this to Realm yourself, just add the following extension:
Which approach is more efficient will likely vary based on the number of objects involved.