How do I count the number of child entities with a specific value?

Discussion in 'iPhone/iPad Programming' started by Mr Skills, Apr 8, 2011.

  1. Mr Skills, Apr 8, 2011
    Last edited by a moderator: Apr 8, 2011

    macrumors 6502a

    Mr Skills

    Joined:
    Nov 21, 2005
    #1
    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:

    Code:
    - (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.

    Code:
        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.
     
  2. ppilone, Apr 8, 2011
    Last edited by a moderator: Apr 8, 2011

    macrumors 6502

    Joined:
    Jan 20, 2008
    #2
    NSManagedObjectContext allows you to count the number of items that would be found using a fetch request (instead of actually fetching those entities).

    Code:
    - (NSUInteger)countForFetchRequest:(NSFetchRequest *)request error:(NSError **)error
    You could change your code to look like this:

    Code:
    - (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.
     
  3. thread starter macrumors 6502a

    Mr Skills

    Joined:
    Nov 21, 2005
    #3
    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 :)
     

Share This Page