CoreData Fetch Request with Most recent Predicate - iphone-sdk-3.0

I have an Entity "Event" which contains a NSDate attribute named "AccidentDate". I am trying to do a fetch request to grab only the most recent 'AccidentDate' but I am not sure how to set up the predicate to grab only the last 'AccidentDate'
Below is my code so far...
NSFetchRequest *fetchRequest1 = [[NSFetchRequest alloc] init];
NSEntityDescription *entity = [NSEntityDescription entityForName:#"Event" inManagedObjectContext:self.managedObjectContext];
[fetchRequest1 setEntity:entity];
NSPredicate *predicate; //unknown code here
[fetchRequest1 setPredicate:predicate];
NSArray *items = [self.managedObjectContext executeFetchRequest:fetchRequest1 error:&error];
[fetchRequest1 release];
Any help would be greatly appreciated. Thanks

You can apply an array of sort descriptors directly to the NSFetchRequest and you can further set its fetch limit to 1. That creates the following code:
NSFetchRequest *fetchRequest1 = [[NSFetchRequest alloc] init];
NSEntityDescription *entity = [NSEntityDescription entityForName:#"Event" inManagedObjectContext:[self managedObjectContext]];
[fetchRequest1 setEntity:entity];
NSSortDescriptor *dateSort = [[NSSortDescriptor alloc] initWithKey:#"accidentDate" ascending:NO];
[fetchRequest1 setSortDescriptors:[NSArray arrayWithObject:dateSort]];
[dateSort release], dateSort = nil;
[fetchRequest1 setFetchLimit:1];
NSManagedObject *latest = [[[self managedObjectContext] executeFetchRequest:fetchRequest1 error:&error] lastObject];
[fetchRequest1 release], fetchRequest1 = nil;

I would fetch all Events sorted by AccidentDate with no predicate and grab the first one from the array.

Related

exclude a property in NSFetchRequest

I need to fetch an entity with all properties expect one property. I know that there is way to include name of all properties to do such a thing:
NSFetchRequest *request = [[NSFetchRequest alloc] init];
[request setResultType:NSDictionaryResultType];
[request setPropertiesToFetch:
[NSArray arrayWithObjects:#"property1", #"property2", /* etc. */ nil]];
NSEntityDescription *e = [NSEntityDescription entityForName:entityName
inManagedObjectContext:self.context];
But I don't want to mention all of properties because of one property!
Do you know any good performance solution for this?
Unfortunately you're going to have to name all properties except the one. There is no other way. Here is a way to do it automatically and don't worry about performance.
NSEntityDescription *entityDescription = [NSEntityDescription entityForName:entityName inManagedObjectContext:self.context];
NSArray *allProperties = entityDescription.properties;
NSMutableArray *propertiesToFetch = [NSMutableArray arrayWithCapacity:allProperties.count];
for (NSPropertyDescription *property in allProperties) {
if (![property.name isEqualToString:#"xxx"]) {
[propertiesToFetch addObject:property];
}
}
NSFetchRequest *request = [NSFetchRequest fetchRequestWithEntityName:entityName];
request.resultType = NSDictionaryResultType;
request.propertiesToFetch = propertiesToFetch;
You can use this approach to remove a particular property from an array of all the properties. Let's assume your Entity is called PatientRecord.
NSFetchRequest *request = [[NSFetchRequest alloc] init];
[request setResultType:NSDictionaryResultType];
PatientRecord *patient;
NSMutableArray *allProperties = [[NSMutableArray alloc] initWithArray:patient.entity.properties];
[allProperties removeObject:#"propertyToRemove"];
[request setPropertiesToFetch:allProperties];
NSEntityDescription *e = [NSEntityDescription entityForName:entityName
inManagedObjectContext:self.context];

Core Data function similar to the WHERE='(sql query)'

How can run sql query CoreData similar this:
SELECT COUNT(*) FROM headphones WHERE id IN (SELECT id FROM old_headphones);
I read NSPredicate guide and NSExpression, but don't understand how to do this.
Try this:
SELECT COUNT(distinct headphones.Id)
FROM headphones
INNER JOIN old_headphones ON
headphones.Id = old_headphones.Id
When there is not an n-to_1 relation between headphones and old_headphones, you can omit the DISTINCT.
/*First request*/
NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init];
NSEntityDescription *entity = [NSEntityDescription
entityForName:#"headphones" inManagedObjectContext:yourContext];
[fetchRequest setEntity:entity];
NSError *error;
NSArray *fetchedObjects = [yourContext executeFetchRequest:fetchRequest error:&error];
/*2nd request*/
NSFetchRequest *fetchRequest2 = [[NSFetchRequest alloc] init];
NSEntityDescription *entity2 = [NSEntityDescription
entityForName:#"old_headphones" inManagedObjectContext:yourContext];
[fetchRequest setEntity:entity2];
NSError *error;
NSArray *fetchedObjects = [yourContext executeFetchRequest:fetchRequest2 error:&error];
//use your 2 NSArray to find your headphones

an NSPredicate for selecting a row with maximum value by group

I'm using Core Data to store entities in the form
TrackerEntry
username
timestamp
I want to select the latest record for each user. Using sql it would be something like
SELECT MAX(timestamp) FROM Log GROUP BY username
Is there anyway to create an NSPredicate to do this?
I would do it using NSExpression. This bit of code below won't work for you because you will have to group by username too, but it's a start for the best way of doing this without having to fetch everything. You want to perform the max and group in the db, not in memory - as it will be faster:
NSFetchRequest *fetchRequest = [[[NSFetchRequest alloc] init] autorelease];
// Expression for the max
NSExpression *keyPathExpression = [NSExpression expressionForKeyPath:#"timestamp"];
NSEntityDescription *entity = [NSEntityDescription entityForName:entityName
inManagedObjectContext:self.coreDataStack.managedObjectContext];
[fetchRequest setEntity:entity];
[fetchRequest setResultType:NSDictionaryResultType];
NSExpression *valueSumExpression = [NSExpression expressionForFunction:#"max:" arguments:[NSArray arrayWithObject:keyPathExpression]];
NSExpressionDescription *expressionDescription = [[[NSExpressionDescription alloc] init] autorelease];
[expressionDescription setName:#"maxTimestamp"];
[expressionDescription setExpression:valueSumExpression];
[expressionDescription setExpressionResultType:NSDecimalAttributeType];
[fetchRequest setPropertiesToFetch:[NSArray arrayWithObject:expressionDescription]];
// Filter
//NSPredicate *pred = [NSPredicate predicateWithFormat:#" your predicate here"];
//fetchRequest.predicate = pred;
NSArray *results = [self.coreDataStack.managedObjectContext executeFetchRequest:fetchRequest error:nil];
if([results count] == 0) {
} else {
// [[results objectAtIndex:0] valueForKey:#"maxTimestamp"];
}
This worked for me, but it is a loop. First you have to get the unique names into an array.
NSFetchRequest *nameRequest = [[NSFetchRequest alloc] init];
NSEntityDescription *entity = [NSEntityDescription entityForName:#"Log" inManagedObjectContext:self.managedObjectContext];
nameRequest.entity = entity;
nameRequest.resultType = NSDictionaryResultType;
[nameRequest setPropertiesToFetch:[NSArray arrayWithObject:[[entity propertiesByName] objectForKey:#"name"]]];
NSArray *allNames = [self.managedObjectContext executeFetchRequest:nameRequest error:nil];
names = [allNames valueForKeyPath:#"#distinctUnionOfObjects.name"];
[nameRequest release];
NSLog(#"%#", names);
Not very efficient or convenient. After all, Core Data is not a database but an object graph.
Then you can loop through these and fetch just the top one.
NSMutableArray *mutableResults = [NSMutableArray array];
NSFetchRequest *request = [[NSFetchRequest alloc] init];
request.entity = [NSEntityDescription entityForName:#"Log" inManagedObjectContext:self.managedObjectContext];
NSSortDescriptor *numberSort = [NSSortDescriptor sortDescriptorWithKey:#"number" ascending:NO];
request.sortDescriptors = [NSArray arrayWithObject:numberSort];
request.fetchLimit = 1;
for (NSString *s in names) {
NSPredicate *pred = [NSPredicate predicateWithFormat:#"name = %#", s];
request.predicate = pred;
NSArray *results = [self.managedObjectContext executeFetchRequest:request error:nil];
[mutableResults addObject:[results objectAtIndex:0]];
}
[request release];
NSLog(#"%#", mutableResults);

How to load all instances of entity / property?

i have some Data in a TableView (loaded from coreData) and now i want to upload this data to a webserver.
Before i can do that i want to save all data to a *.txt file.
How can i load all instances of an entity / property to an mutable array?
NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init];
NSEntityDescription *entity = [NSEntityDescription entityForName:#"Event" inManagedObjectContext:self.managedObjectContext];
[fetchRequest setEntity:entity];
[fetchRequest setFetchBatchSize:20];
NSSortDescriptor *sortDescriptor = [[NSSortDescriptor alloc] initWithKey:#"barCode" ascending:NO];
NSArray *sortDescriptors = [[NSArray alloc] initWithObjects:sortDescriptor, nil];
Thanks,
brush51
Edit 1:
Can you give me a little Help (i dont want ALL data, just the property "barCode"), now i have this code:
NSManagedObjectContext *moc = [self managedObjectContext];
NSFetchRequest *req = [[NSFetchRequest alloc] init];
[req setEntity:[NSEntityDescription entityForName:#"Event" inManagedObjectContext:moc]];
[req setIncludesPropertyValues:NO];
NSError *error;
NSArray *codes = [moc executeFetchRequest:req error:&error];
[req release];
for (NSManagedObject *Event in codes) {
NSLog(#"there it is : ------------> %#", codes);
NSLog(#"barcodes ------------------> %#", [[managedObject valueForKey:#"barCode"] description]);
}
How to output ONLY the instances of the property "barCode" ??
thanks for answering,
here is my code:
NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init];
NSEntityDescription *entity = [NSEntityDescription entityForName:#"Event" inManagedObjectContext:self.managedObjectContext];
[fetchRequest setEntity:entity];
[fetchRequest setFetchBatchSize:20];
NSSortDescriptor *sortDescriptor = [[NSSortDescriptor alloc] initWithKey:#"barCode" ascending:NO];
NSArray *sortDescriptors = [[NSArray alloc] initWithObjects:sortDescriptor, nil];
I have no predicate... Predicate is for what?
If you do a fetch request on the entity without a predicate, you'll get all the instances.

Core Data: keypath name not found in entity

I'm crashing with this message :
'NSInvalidArgumentException', reason: 'keypath name not found in entity
Obvisouly I'm not querying my entity correctly .
//fetching Data
NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init];
NSManagedObjectContext *context = [(AppDelegate *)[[UIApplication sharedApplication] delegate] managedObjectContext];
NSEntityDescription *entity = [NSEntityDescription entityForName:#"Viewer" inManagedObjectContext:context];
[fetchRequest setEntity:entity];
NSString *attributeName = #"dF";
NSPredicate *predicate = [NSPredicate predicateWithFormat:#"name like %#",attributeName];
[fetchRequest setPredicate:predicate];
NSLog(#"predicate : %#",predicate);
NSError *error;
NSArray *items = [context executeFetchRequest:fetchRequest error:&error];
NSLog(#"items : %#",items);
[fetchRequest release];
//end of fetch
And here is my data Model:
I want to return the value of "dF", shouldn't call it like this ? :
NSString *attributeName = #"dF";
NSPredicate *predicate = [NSPredicate predicateWithFormat:#"name like %#",attributeName];
If you want to get value from your dF property, you have to fetch an array of NSManagedObjects and then use [fetchedManagedObject valueForKey:#"dF"]; to get your value.
NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init];
NSManagedObjectContext *context = [(AppDelegate *)[[UIApplication sharedApplication] delegate] managedObjectContext];
NSEntityDescription *entity = [NSEntityDescription entityForName:#"Viewer" inManagedObjectContext:context];
[fetchRequest setEntity:entity];
NSArray *items = [context executeFetchRequest:fetchRequest error:&error];
[fetchRequest release];
NSManagedObject *mo = [items objectAtIndex:0]; // assuming that array is not empty
id value = [mo valueForKey:#"dF"];
Predicates are used to get array of NSManagedObjects that satisfy your criteria. E.g. if your dF is a number, you can create predicate like "dF > 100", then your fetch request will return an array with NSManagedObjects that will have dF values that > 100. But if you want to get just values, you don't need any predicate.
I was using a NSSortDescriptor initialized with a String key:
let fetchRequest = NSFetchRequest<SomeManagedObject>(entityName: "SomeManagedObject")
let sortDescriptor = NSSortDescriptor(key: "name", ascending: true)
fetchRequest.sortDescriptors = [sortDescriptor]
I then changed the name of the name attribute in the model. Refactored all of the property names, but didn't catch the stringly typed key: "name".
The solution for Swift is to use NSSortDescriptor(keyPath: instead, which will fail to compile if the property key path changes.
NSSortDescriptor(keyPath: \SomeManagedObject.firstName, ascending: true)