How to count in coredata (aggregation)?

2019-03-16 09:11发布

问题:

I am learning core data and particularly working on aggregation.

Current what I want to do : count the number of records from the table which is in to-many relationship with inverse relationship on some criteria.

Currently I am doing this :

NSExpression *ex = [NSExpression expressionForFunction:@"count:" 
                                                 arguments:[NSArray arrayWithObject:[NSExpression expressionForKeyPath:@"ddname"]]];
    NSPredicate *pred = [NSPredicate predicateWithFormat:@"ddtype == 'Home'"];
    NSExpressionDescription *ed = [[NSExpressionDescription alloc] init];
    [ed setName:@"countDDEvents"];
    [ed setExpression:ex];
    [ed setExpressionResultType:NSInteger16AttributeType];
    NSArray *properties = [NSArray arrayWithObject:ed];
    NSFetchRequest *request = [[NSFetchRequest alloc] init];
    [request setPredicate:pred];
    [request setPropertiesToFetch:properties];
    [request setResultType:NSDictionaryResultType];
    NSEntityDescription *entity = [NSEntityDescription entityForName:@"DDEvent" inManagedObjectContext:[self.currentAccount managedObjectContext]];
    [request setEntity:entity];
    NSArray *results = [[self.currentAccount managedObjectContext] executeFetchRequest:request error:nil]; 
    NSDictionary *dict = [results objectAtIndex:0];
    NSLog(@"Average birthdate for female heroes: %@", [dict objectForKey:@"countDDEvents"]);

Its from jeff lemarche.

EDIT : and I have found my solution as

    NSFetchRequest *request = [[NSFetchRequest alloc] init];
    NSPredicate *pred = [NSPredicate predicateWithFormat:@"ddtype == 'Home'"];
    [request setPredicate:pred];

    NSEntityDescription *entity = [NSEntityDescription entityForName:@"DDEvent" inManagedObjectContext:[self.currentAccount managedObjectContext]];
    [request setEntity:entity];

    NSError *error = nil;
    NSUInteger count = [[self.currentAccount managedObjectContext] countForFetchRequest:request error:&error];

It is working nicely .But I want to do more request of such type at a time . So i think this can't be a preferred way of getting the count .

EDIT :

So I think the approach would be the appropriate one ????

So can anyone tell me more efficient an preferred way of doing this .

Thanks .

回答1:

Jeff LaMarche is just using this as a simple example. In practice, this need is so common that Key-Value Coding has a built in macro to handle it and other common collection operations.

See: The Key-Value Programming Guide: Set and Array Operators

In this case you would use the @count operator in your predicate.

Of course, hand tuning your own expression gives you fine control over your predicates but the operators handle 80% of such task.



回答2:

I had to count about 10 000 entities and it slowed down my interface responsiveness a lot while doing it with countForFetchRequest..

Here is a way of doing it wth NSExpression:

- (NSUInteger) unfilteredFCsCount {

// Just the fetchRequest
    NSFetchRequest *fetchRequest = [self unfilteredFCsFetchRequest];

    [fetchRequest setResultType: NSDictionaryResultType];

// You can use any attribute of the entity. its important, because you are not counting 
// the properties, but actually the entities
    NSExpression *keyPathExpression = [NSExpression expressionForKeyPath: @"sortIndex_"]; // Does not really matter
    NSExpression *maxExpression = [NSExpression expressionForFunction: @"count:" 
                                                            arguments: [NSArray arrayWithObject:keyPathExpression]];
    NSExpressionDescription *expressionDescription = [[NSExpressionDescription alloc] init];
    [expressionDescription setName: @"fcCount"];
    [expressionDescription setExpression: maxExpression];
    [expressionDescription setExpressionResultType: NSInteger32AttributeType];

    [fetchRequest setPropertiesToFetch: [NSArray arrayWithObject:expressionDescription]];

    NSUInteger fcCount = 0;
    NSError *error = nil;
    NSArray *results = nil;
    results = [self.managedObjectContext executeFetchRequest: fetchRequest error: &error];
    KSLog(KSLogLevelDebug, @"unfilteredFCsCount results: %@", results);

    if([results count] > 0) {
        NSNumber *count = [[results objectAtIndex: 0] objectForKey: @"fcCount"];
        fcCount = [count intValue];
    }

    return fcCount;
}