Realm-cocoa: Support queries on inverse relationships (backlinks)

Created on 12 Jan 2015  路  26Comments  路  Source: realm/realm-cocoa

It looks like the only way I can query inverse relationships is to create explicit links instead of using the recommendation for creating inverse relationships found in the docs (http://realm.io/docs/cocoa/#relationships).

Note: creating explicit links is explained here: https://github.com/realm/realm-cocoa/issues/677#issuecomment-50182237

T-Enhancement

Most helpful comment

See #3419 to get a preview of the API for this.

All 26 comments

Thanks for filing this, @joshuadutton. We agree that it would be nice to expose a more direct way to do this through property-backed inverse relationships, though it is possible to do many queries involving inverse relationships today.

If you have a specific query you'd like to make, you can post it here and we might be able to find a way to do that using our current API.

I have an Asset class that has a to-many relationship with a Tag class so that an asset can have multiple tags. My Tag class has an inverse relationship so I can see which assets have been tagged with a given tag.

Given a bunch of assets, I want a query that will return all the tags they collectively have. I assumed this would work:

[Tag objectsWhere:@"ANY assets IN %@", assets]

This throws an error with the way I have implemented the inverse relationship since the assets property is not stored in the database.

Edit: The above query works with an explicit link.

I have a problem related to this issue

@interface Big : RLMObject
@property(readonly) NSArray *smallArray;
@end
@implementation Big
- (NSArray *)smallArray {
    return [self linkingObjectsOfClass:@"Small" forProperty:@"big"];
}
@end

@interface Small : RLMObject
@property Big *big;
@end

Need to delete all Big where smallArray.count == 0.
I made it this way:

RLMResults *bigs = [Big allObjectsInRealm:realm];
    for (Big *item in bigs) {
        if (item. smallArray.count == 0) {
            [realm transactionWithBlock:^{
                [realm deleteObject:item];
            }];
        }
    }

Any way to make it like [realm deleteObjects:[Big allObjectsInRealm:realm where:@"smallArray.count = 0"]]?

@Kirow count queries are not yet supported. There is an open issue for it here #1166

count queries are not yet supported

Even if they were, it's not possible to include a property that isn't stored in Realm in a predicate (e.g. smallArray in this case).

What necessary for the time being is to formulate a predicate based on the results of calling linkingObjectsOfClass:forProperty:.

I just ran into this as well and as @joshuadutton mentioned, (until this is supported) it can be worked around via explicit relationship.

Just wanted to chime and say that this would be great. We recently ran into an issue where we tried to filter on an inverse relationship and stumbled upon this. I see that the issue blocked, but simply wanted to state how nice it would be to be able to use inverse relationships to efficiently filter results. Thanks!

@bcapps there's actually an open PR that adds this. The blocked tag can probably be removed now.

Suppose we have model like this:

class Car : Object {
   var owner: Person? {
        return linkingObjects(Person.self, forProperty: "cars").first
    }
}

It would be great if we have simple way to find all cars with no owner, like realm.objects(Car).filter("owner is NULL")

@siuying yes, that's part of what this issue is tracking.

+1 for this feature

+1, any updates on this ? In my opinion one of the most frustrating thing about Realm right now.

+1, any updates on this ? In my opinion one of the most frustrating thing about Realm right now.

Agreed. We're actively working on it.

+1 for this feature

  • 1 for this feature as well.

Another +1

Any updates ?

+1

Any update on that one?

I started working on this earlier this week. I'll update this issue when I have something to share.

+1

+1, looking forward to seeing your solution for this

+1

See #3419 to get a preview of the API for this.

Hi @bdash
I have related issue.
I have Friend class and a FriendGroup class. FriendGroup has a to may relation to Friend also, Friend has an inverse relation to FriendGroup. Now I want to fetch all friends to a Results<Friend> who are not added to any groups.

My class declaration is like,

class Friend: Object {
    @objc dynamic var name = ""
    let group = LinkingObjects(fromType: FriendGroup.self, property: "members")    
}

class FriendGroup: Object {
    @objc dynamic var name = ""

    let members = List<Friend>()
}

And I tried fetching like

let predicae = NSPredicate(format: "group.count < %ld", 1)
friends = realm?.objects(Friend.self).filter(predicae).sorted(byKeyPath: "name")

But its crashing with stack trace

*** Terminating app due to uncaught exception 'Invalid property name', reason: 'Property 'count' not found in object of type 'FriendGroup''
*** First throw call stack:
(
    0   CoreFoundation                      0x0000000106ca51cb __exceptionPreprocess + 171
    1   libobjc.A.dylib                     0x0000000105a2bf41 objc_exception_throw + 48
    2   Realm                               0x000000010465e4c1 _ZL15RLMPreconditionbP8NSStringS0_z + 657
    3   Realm                               0x0000000104666b97 _ZN12_GLOBAL__N_120key_path_from_stringEP9RLMSchemaP15RLMObjectSchemaP8NSString + 1015
    4   Realm                               0x0000000104663f8c _ZN12_GLOBAL__N_112QueryBuilder30column_reference_from_key_pathEP15RLMObjectSchemaP8NSStringb + 140
    5   Realm                               0x0000000104662fa2 _ZN12_GLOBAL__N_112QueryBuilder22apply_value_expressionEP15RLMObjectSchemaP8NSStringP11objc_objectP21NSComparisonPredicate + 338
    6   Realm                               0x0000000104660033 _ZN12_GLOBAL__N_112QueryBuilder15apply_predicateEP11NSPredicateP15RLMObjectSchema + 5075
    7   Realm                               0x000000010465e67b _Z19RLMPredicateToQueryP11NSPredicateP15RLMObjectSchemaP9RLMSchemaRN5realm5GroupE + 347
    8   Realm                               0x000000010479b57b _ZZ35-[RLMResults objectsWithPredicate:]ENK4$_11clEv + 283
    9   Realm                               0x0000000104795206 _ZL15translateErrorsIZ35-[RLMResults objectsWithPredicate:]E4$_11EDaOT_P8NSString + 38
    10  Realm                               0x0000000104795188 -[RLMResults objectsWithPredicate:] + 72
    11  RealmSwift                          0x00000001050e0459 _T010RealmSwift7ResultsC6filterACyxGSo11NSPredicateCF + 153
    12  Invite                              0x00000001041a4212 _T06Invite20ImportViewControllerC11viewDidLoadyyF + 514
    13  Invite                              0x00000001041a4a94 _T06Invite20ImportViewControllerC11viewDidLoadyyFTo + 36
    14  UIKit                               0x0000000107844d51 -[UIViewController loadViewIfRequired] + 1235
    15  UIKit                               0x000000010784519e -[UIViewController view] + 27
    16  UIKit                               0x000000010787713b -[UINavigationController _startCustomTransition:] + 954
    17  UIKit                               0x000000010788d894 -[UINavigationController _startDeferredTransitionIfNeeded:] + 686
    18  UIKit                               0x000000010788eb90 -[UINavigationController __viewWillLayoutSubviews] + 115
    19  UIKit                               0x0000000107ae52ae -[UILayoutContainerView layoutSubviews] + 231
    20  UIKit                               0x0000000107775551 -[UIView(CALayerDelegate) layoutSublayersOfLayer:] + 1331
    21  QuartzCore                          0x000000010f85f4ba -[CALayer layoutSublayers] + 153
    22  QuartzCore                          0x000000010f8635a9 _ZN2CA5Layer16layout_if_neededEPNS_11TransactionE + 401
    23  QuartzCore                          0x000000010f7ec1cd _ZN2CA7Context18commit_transactionEPNS_11TransactionE + 365
    24  QuartzCore                          0x000000010f817ae4 _ZN2CA11Transaction6commitEv + 500
    25  QuartzCore                          0x000000010f818830 _ZN2CA11Transaction17observer_callbackEP19__CFRunLoopObservermPv + 76
    26  CoreFoundation                      0x0000000106c47db7 __CFRUNLOOP_IS_CALLING_OUT_TO_AN_OBSERVER_CALLBACK_FUNCTION__ + 23
    27  CoreFoundation                      0x0000000106c47d0e __CFRunLoopDoObservers + 430
    28  CoreFoundation                      0x0000000106c2c324 __CFRunLoopRun + 1572
    29  CoreFoundation                      0x0000000106c2ba89 CFRunLoopRunSpecific + 409
    30  GraphicsServices                    0x000000010e37e9c6 GSEventRunModal + 62
    31  UIKit                               0x00000001076a6d30 UIApplicationMain + 159
    32  Invite                              0x000000010419b2e7 main + 55
    33  libdyld.dylib                       0x000000010743bd81 start + 1
)
libc++abi.dylib: terminating with uncaught exception of type NSException

group is a LinkingObjects object, then why its crashing

@jkmathew, if you have a question please either ask it on Stack Overflow (we monitor the realm tag) or in a new issue. Please don't just dump it on the end of an issue that's been closed for 18 months.

Was this page helpful?
0 / 5 - 0 ratings