Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Core data - nested sum with where condition

I have a application that show the amount sold by a store all the time.

NSNumber *amount = [self valueForKeyPath:@"[email protected]"];

Now i have to filter and show the amount by period. I have the field "period" (string) that holds month and year, like "2012-11".

How can i make the same query using the where clause?

like image 804
franciscomxs Avatar asked May 29 '26 04:05

franciscomxs


1 Answers

You can filter the sales before computing the sum.

NSPredicate *predicate = [NSPredicate predicateWithFormat:@"period == %@", @"2012-11"];
NSSet *sales = [self valueForKeyPath:@"sales"];
NSSet *filteredSales = [sales filteredSetUsingPredicate:predicate];
NSNumber *amount = [filteredSales valueForKeyPath:@"@sum.value"];

But when you have many dozens or more sales, this method is not really efficient because it requires to load each sale into memory.

Moreover, if the sales are in fault, each sale will fire a fault and generate a SQL request. You may prevent this by batch faulting the sales before filtering them.

We will assume that self is a managed object.

NSPredicate *predicate = [NSPredicate predicateWithFormat:@"period == %@", @"2012-11"];
NSSet *sales = [self valueForKeyPath:@"sales"];
// Begin batch-faulting
NSManagedObjectContext *moc = [self managedObjectContext];
NSFetchRequest *request = [NSFetchRequest new];
[request setEntity:[NSEntityDescription entityForName:@"Sale" inManagedObjectContext:moc]];
[request setPredicate:[NSPredicate predicateWithFormat:@"self IN %@", sales]];
[request setReturnsObjectsAsFaults:NO];
[moc executeFetchRequest:request error:NULL];
// Batch-faulting done
NSSet *filteredSales = [sales filteredSetUsingPredicate:predicate];
NSNumber *amount = [filteredSales valueForKeyPath:@"@sum.value"];

However, you still get several allocations for each sale (the managed object, its cache, its attributes). The best solution is to use a fetch request to compute the sum in the SQLite database.

NSString *reverseRelationship = @"store"; // name of the relationship from the sale to self
NSExpressionDescription *description = [NSExpressionDescription new];
[description setName:@"amount"];
[description setExpressionResultType:NSDoubleAttributeType];
[description setExpression:[NSExpression expressionWithFormat:@"@sum.value"]];
NSManagedObjectContext *moc = [self managedObjectContext];
NSFetchRequest *request = [NSFetchRequest new];
[request setEntity:[NSEntityDescription entityForName:@"Sale" inManagedObjectContext:moc]];
[request setResultType:NSDictionaryResultType];
[request setPredicate:[NSPredicate predicateWithFormat:
                       @"%K == %@ AND period == %@", reverseRelationship, self, @"2012-11"]];
[request setPropertiesToFetch:@[description]];
NSDictionary *result = [[moc executeFetchRequest:request error:NULL] lastObject];
NSNumber *amount = [result objectForKey:@"amount"];
like image 111
Nicolas Bachschmidt Avatar answered May 31 '26 06:05

Nicolas Bachschmidt



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!