Master data selection queries in a nested tree structure

So, I just enjoy using Core Data and started integrating it into the application I'm working on. However, I ran into an issue for which I don't see an obvious solution that makes me feel like Core Data might not be the right tool for the job. Here's the situation: I have a tree Node

s, each of which may or may not have children. There can be arbitrarily many root Node

s. I put together a data model using to-many relationships (from Node

to Node

s) with one inverse relationship. Everything is good.

Now each Node

also has a to-many relation to Record

s, which also has a feedback with an inverse relation to Node

. I want to find all Record

that have a certain boolean attribute set to true, and somewhere below the given one Node

. It was very simple before I used Core Data - I just walk the tree. However, it takes a long time, and I was hoping Core Data would give me the ability to just do a fetch query that would grab everything quickly Record

. I can figure out how to do this (semi) easily if I know the maximum depth I want to check, but what if I want to go all the way down? What if everyone Node

has children?

Should I just walk the tree like I did before?

Is it NSFetchRequest

even capable of performing such a task?

+3


source to share


1 answer


This is not a basic data problem, but a graph problem. You must do the same search. However, CoreData can let you crash on objects. So you have several options, two of which are

1) Walk the tree. You should be able to use the same algorithm that you used with the tree in memory. CoreData should just blame objects. Unless you have an extremely deep tree, you should be fine.

2) Encode the parenting relationship in each entry. Fair number of updates when the tree is updated, but the selections will be faster.



The following can be converted to NSCompoundPredicate and assigned as a select predicate ... The docs say this works on CoreData, but not sqllite - try it.

NSPredicate *nodePredicate = [NSPredicate predicateWithFormat:@"field = %@", value];
// Use nodePredicate to find ones that match the ones you want to find
// Then use a block predicate to see if the parent is there.
NSArray *potential = [context executeFetchRequest:fetchRequest error:&error];
if (!error) {
    NSPredicate *parentPredicate = [NSPredicate predicateWithBlock:^BOOL(id obj, NSDictionary *bindings) {
        Node *node = obj;
        while (node) {
            if ([node.parent.nodeId isEqualToString:targetId) return YES;
            node = node.parent;
        }
        return NO;
    }];
    NSArray *foundNodes = [potential filteredArrayUsingPredicate:parentPredicate];
}

      

+2


source







All Articles