PDA

View Full Version : How do I count the number of child entities with a specific value?




Mr Skills
Apr 8, 2011, 10:43 AM
My entity "Checklist" has a to-many relationship ("checklistItems") with the entity ChecklistItem. ChecklistItem has a bool attribute called "checked".

While in my app's Checklist View, I want to find out how many of each checklist's items are checked. This is the code I have come up with:

- (void)configureCell:(UITableViewCell *)cell atIndexPath:(NSIndexPath *)indexPath
{
Checklist *aChecklist = [self.fetchedResultsController objectAtIndexPath:indexPath];
cell.textLabel.text = aChecklist.name;

NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init];
NSEntityDescription *entity = [NSEntityDescription entityForName:@"Checklist" inManagedObjectContext:self.managedObjectContext];
[fetchRequest setEntity:entity];

NSPredicate *predicate = [NSPredicate predicateWithFormat:@"any self.checklistItems.checked = %@", [NSNumber numberWithBool:YES]];
[fetchRequest setPredicate:predicate];

NSError *error = nil;
NSArray *results = [self.managedObjectContext executeFetchRequest:fetchRequest error:&error];

cell.detailTextLabel.text = [NSString stringWithFormat:@"%i items ticked", [results count]];
[fetchRequest release];
}

Unfortunately, this just returns the total number of Checklists that have any item checked. What am I doing wrong?

(Thanks!)

EDIT:

I'm getting a little closer... changing the predicate to the following will give me a 1 if any item is checked, and a 0 if no item is checked. It's still not counting the number of checked items, but at least it's pointing at the right checklist.

NSPredicate *predicate = [NSPredicate predicateWithFormat:@"(name == %@) && (ANY checklistItems.checked in %@)", aChecklist.name, [NSArray arrayWithObject:[NSNumber numberWithBool:YES]]];

EDIT:

I've come up with a different way of going about it. I added a "numberChecked" attribute to my Checklist property, which I increment every time an item is ticked, a decrement every time an item is unticked.

This works fine, although I'd love to know if anyone has a way of querying this without having to make it part of my data model.



ppilone
Apr 8, 2011, 02:15 PM
NSManagedObjectContext allows you to count the number of items that would be found using a fetch request (instead of actually fetching those entities).

- (NSUInteger)countForFetchRequest:(NSFetchRequest *)request error:(NSError **)error

You could change your code to look like this:

- (void)configureCell:(UITableViewCell *)cell atIndexPath:(NSIndexPath *)indexPath
{
Checklist *aChecklist = [self.fetchedResultsController objectAtIndexPath:indexPath];
cell.textLabel.text = aChecklist.name;

NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init];
NSEntityDescription *entity = [NSEntityDescription entityForName:@"CheckListItem" inManagedObjectContext:self.managedObjectContext];
[fetchRequest setEntity:entity];

NSPredicate *predicate = [NSPredicate predicateWithFormat:@"self.checklist == %@ AND self.checked == YES", aChecklist];
[fetchRequest setPredicate:predicate];

NSError *error = nil;
NSInteger numResults = [self.managedObjectContext countForFetchRequest:fetchRequest error:&error];

cell.detailTextLabel.text = [NSString stringWithFormat:@"%i items ticked", [results count]];
[fetchRequest release];
}

Note the change in the fetch request, predicate and the line that executes the fetch request. (I'm also assuming the name of the checklist<->checklistitem relationship in the predicate).

EDIT:

Since you have the check list you could also just filter the checkListItem set for the checklist using a predicate and take the count of filtered set. This way you don't have to fetch anything.

Mr Skills
Apr 8, 2011, 03:49 PM
Thanks @ppilone! I also asked on Stack Overflow where someone came up with the same idea of filtering the set, so that's what I've gone with. But I didn't know about "countForFetchedRequest:" so I've learned something new :)