How to fetch specific records in Core data - ios

I am a new bid in iOS development. I am using NSManagedObject of Core Data to perform Insert and Fetch operations. It works perfectly fine. But the problem is, I want to fetch only some selected records (where condition in MySQL) from the table.
For e.g. "select name from users where city='Pune'";
I found NSPredicate to fetch filtered data. But it gives all the data in array and not just the selected one. For e.g. if result for above query is:
Anu
Then the NSPredicate result will give:
fname = Anu
lname = Padhye
city = Pune
id = 3
Is there a way to only fetch selected record/s in iOS Objective-c? Following is the code snippet I am using for NSManagedObject:
NSManagedObjectContext *managedObjectContext = [self managedObjectContext];
NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] initWithEntityName:#"User"];
valueData = [[managedObjectContext executeFetchRequest:fetchRequest error:nil] mutableCopy];
NSEntityDescription *productEntity=[NSEntityDescription entityForName:#"User" inManagedObjectContext:managedObjectContext];
NSFetchRequest *fetch=[[NSFetchRequest alloc] init];
[fetch setEntity:productEntity];
NSPredicate *p=[NSPredicate predicateWithFormat:#"id == %d", 3];
[fetch setPredicate:p];
//... add sorts if you want them
NSError *fetchError;
NSArray *fetchedProducts=[valueData filteredArrayUsingPredicate:p];

Try this:
NSFetchRequest *request = [[NSFetchRequest alloc] initWithEntityName:#"User"];
request.predicate = [NSPredicate predicateWithFormat:#"city == %# && id == %d", #"Pune", 3];
request.sortDescriptors = #[[NSSortDescriptor sortDescriptorWithKey:#"id" ascending:YES]];
NSArray *results = [managedObjectContext executeFetchRequest:request error:nil];
Results array should now contain all records who have Pune as their city with the id of 3.

Related

NSPredicate to check property of first 5 objects in a Core Data Relationship

I am looking to create a predicate that can check the TypeID of the first 5 objects in a Core Data relationship.
Here is what I am trying, but it doesn't work:
int num = 5;
NSMutableArray *predicates = [[NSMutableArray alloc] init];
for (int i = 0; i < num; i++) {
[predicates addObject:[NSPredicate predicateWithFormat:#"SELF IN %# AND logs[%i].TypeID == 3", items, i]];
}
This gives the error:
error: SQLCore dispatchRequest: exception handling request:
< NSSQLFetchRequestContext: 0x281837aa0 > , Unsupported function
expression logs[0].TypeID with userInfo of (null) CoreData:
error: SQLCore dispatchRequest: exception handling request:
< NSSQLFetchRequestContext: 0x281837aa0 > , Unsupported function
expression logs[0].TypeID with userInfo of (null)
I realize I am probably doing this wrong, so is there a different way that I could be doing this using NSPredicate?
if you want only fetch 5. Set fetchLimit to 5. Maybe the following code can not run right away, but the principle is same. You can add a property or get function to assign the "logs.TypeID" like -(Int)myID {return logs[0].TypeID;} then "SELF IN %# AND myID == 3" would solve the problem.
NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init];
NSEntityDescription *entity = [NSEntityDescription entityForName:#"Entity name" inManagedObjectContext:context];
[fetchRequest setEntity:entity];
NSPredicate *predicate = [NSPredicate predicateWithFormat:#"SELF IN %# AND logs.TypeID == 3", items];
[fetchRequest setPredicate:predicate];
fetchRequest.fetchLimit = 5;
NSError *error = nil;
NSArray *fetchedObjects = [context executeFetchRequest:fetchRequest error:&error];
if (fetchedObjects == nil) {
}
I’m not sure I understand the questions, but I don’t think it’s possible to do what you asked, at least not as worded. It doesn’t seem like it would be possible to inspect only five objects in the relationship and stop there, returning any number of matches or none at all, even if there are more in the database.
However, and I think this may be what you were getting at, it is possible to find five objects that are both in the items set and have at least one log with a typeID == 3. It can be done similar to what E.Coms proposed, except you need a subquery to handle the relationship. (I am assuming logs is a to-many relationship, either one-to-many or many-to-many).
Note that the following code has not been tested:
NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init];
NSEntityDescription *entity = [NSEntityDescription entityForName:#"Entity name" inManagedObjectContext:context];
[fetchRequest setEntity:entity];
NSPredicate *predicate = [NSPredicate predicateWithFormat:#"SELF IN %# AND SUBQUERY(logs, $log, $log.typeID == 3).#count != 0", items];
[fetchRequest setPredicate:predicate];
fetchRequest.fetchLimit = 5;
NSError *error = nil;
NSArray *fetchedObjects = [context executeFetchRequest:fetchRequest error:&error];
if (fetchedObjects == nil) {
}

Using NSPredicate and Joins

I have 2 tables: Users and Comments like so:
Users
user_id (PK)
name
Comments
comment_id (PK)
user_id
comment
I want to get a list of all users and their comments.
How is this done using NSPredicate?
Thanks.
As far as I understood your question, you are using core-data.
First of all, you have to make a small change in your managed object model.
Entity
Users
Attributes
user_id
name
Entity
Comments
Attributes
comment_id
comment
Relationships
Relationship - - - Desination - - - Inverse
user - - - Users - - - NO Inverse
Now , whenever you enter the data for Comments object, associate a user relationship with it as
comment.user=theUser
where theUser is a 'Users' object which you can get from 'Users' table by comparing user_id, for that you can use a simple method as by calling the following method for the userID that you got from comment data
theUser= [self isUserAlreadyExistsWithUserID:userID];
where the method definition could be like in Users NSManagedObject subclass
+(NSManagedObject*)isUserAlreadyExistsWithUserID uniqueValue: (id)uniqueValue
{
NSManagedObjectContext* context=[self managedObjectContext];
NSError*error=nil;
NSEntityDescription *entity = [NSEntityDescription entityForName:#"Users" inManagedObjectContext:context];
NSPredicate *predicate = [NSPredicate predicateWithFormat:#"user_id = %#",uniqueValue];
NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init];
fetchRequest.entity = entity;
[fetchRequest setPredicate:predicate];
NSArray *objects = [context executeFetchRequest:fetchRequest error:&error];
if(objects && objects.count>0)
{
return [objects objectAtIndex:0];
}
else
{
return nil;
}
}
Now, to fetch comments for particular user in comments NSManagedObject subClass:
+(NSFetchedResultsController*)getCommentsForUser:(Users*)user
{
NSString* cacheName=#"Root";
[NSFetchedResultsController deleteCacheWithName:cacheName];
NSManagedObjectContext* context=[self managedObjectContext];
NSEntityDescription *entity = [NSEntityDescription entityForName:NSStringFromClass([self class]) inManagedObjectContext:context];
NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init];
[fetchRequest setEntity:entity];
NSPredicate* predicate=[NSPredicate predicateWithFormat:#"user=%#",user];
fetchRequest setPredicate:predicate];
NSFetchedResultsController *theFetchedResultsController = [[NSFetchedResultsController alloc] initWithFetchRequest:fetchRequest
managedObjectContext:context sectionNameKeyPath:nil
cacheName:cacheName];
return theFetchedResultsController;
}
Hope this helps.
I think, you need this query:
SELECT Users.*,Comments.comment_id,Comments.comment FROM Users LEFT JOIN Comments ON Users.user_id = Comments.user_id;
This will return list of all users along with their comments. You can modify it, as per your specific requirements.
Are you using CoreData? if yes then use try the following code:
NSEntityDescription *entityDescription = [NSEntityDescription entityForName:#"Users" inManagedObjectContext:self.managedObjectContext];
NSFetchRequest *request = [[NSFetchRequest alloc] init];
[request setEntity:entityDescription];
[request setRelationshipKeyPathsForPrefetching:[NSArray arrayWithObjects:#"Comments",nil]];
[request setIncludesSubentities:YES];
NSArray* returnArray = [self.managedObjectContext executeFetchRequest:request error:&error];
if([returnArray count] > 0)
{
Users* user = [returnArray objectAtIndex:0];
NSLog(#"%# %# %#", user.user_id, user.name, user.userComments.comment);
}
Also, CoreData uses relationships instead of foreignKeys. Therefore, to get this working you need to setup an inverse relationship userComments (many to one) from Comments to Users.
It is better not to use NSPredicate when making a query. You can simply write a JOIN query. As Apple's documentation also states that the NSPredicate class is used to define logical conditions used to constrain a search either for a fetch or for in-memory filtering. Also it will be easier to use Key-Value Coding. Here is a good explaination to how it can be used. Lets assume you have NSSet of Comments. You can do something like :
[Comments valueForKeyPath:#"users.user_id"];
But, if you really want to use NSPredicate following is the possible way:
NSFetchRequest *fetchReq = [[NSFetchRequest alloc] initWithEntityName:#"Users"];
NSError *error;
NSPredicate *predicate = [NSPredicate predicateWithFormat:#"(user_id == %#)",Comments.user_id];
[fetchReq setPredicate:predicate];
NSArray *result = [self.managedObjectContext executeFetchRequest:fetchReq error:&error];

Validating data and looping through NSSet

I have a CoreData (SQLite) datamodel in xcode like so:
Friends Table
email
name
username
belongsToGroups
Groups Table
title
peopleInGroup
So the belongsToGroups and peopleInGroups is a many-to-many relationship with each other, both represented by NSSet in the code.
What do I use to query the NSSet for people in my groups and vice versa? (I'm new to CoreData)
With coredata, you can do it simple. Assume we have one object on Groups Table ( group), you want to get all friends belong to group, you can do:
[group. peopleInGroup allObjects]
For more detail:
Get group via title
NSError* error = nil;
NSFetchRequest* fetchRequest = [[NSFetchRequest alloc] init];
NSPredicate *predicate;
NSEntityDescription *entity;
NSArray *fetchedObjects;
Group* group;
entity = [NSEntityDescription
entityForName:[NSString stringWithFormat:#"%#",[Group class]]
inManagedObjectContext:self.managedObjectContext];
[fetchRequest setEntity:entity];
predicate = [NSPredicate predicateWithFormat:[NSString stringWithFormat:#"(title like[c] \"%#\")" ,title]];
[fetchRequest setPredicate:predicate];
fetchedObjects = [self.managedObjectContext executeFetchRequest:fetchRequest error:&error];
if (fetchedObjects.count > 0) {
group = [fetchedObjects lastObject];
}
return group;
}
Get all friend of group
NSMutableArray* friends = [NSMutableArray alloc] init];
[friends addObjectsFromArray:[group. peopleInGroup allObjects]];

fetching specific data from core data database and displaying in UITableView

I currently have a table view that displays all the contents of the database Entity: ExData.
ExData has an attribute tag of string type.
What my problem is that i would like to display the contents of the ExData in the table view but only the entries that have a tag set of 2 for example.
The tag is to be sent from the previous view controller but this can be sorted out later as firstly i would just like to hard code only one tag value entries being displayed
ExDatasArray is a mutable Array.
NSManagedObjectContext *managedObjectContext = [self managedObjectContext];
NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] initWithEntityName:#"ExData"];
self.ExdatasArray = [[managedObjectContext executeFetchRequest:fetchRequest error:nil] mutableCopy];
Above is how the data from ExData is being fetched...
To fetch specific data, you add a predicate to the fetch request:
NSString *theTag = ...
NSPredicate *predicate = [NSPredicate predicateWithFormat:#"tag == %#", theTag];
[fetchRequest setPredicate:predicate];
Remark: If you are displaying the result set in a table view, you might also consider to
use a NSFetchedResultsController.
If I understand your question correctly, you are trying to limit the results of the fetchRequest. Use an NSPredicate to specify the query and if desired an NSSortDescriptor to sort it. Below I assume that your tag attribute is named tag, and that searchTagValue has been set appropriately.
NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] initWithEntityName:#"ExData"];
fetchRequest.predicate = [NSPredicate predicateWithFormat:#"tag == %#", searchTagValue];
fetchRequest.sortDescriptors = [NSArray arrayWithObject:[NSSortDescriptor sortDescriptorWithKey:#"tag" ascending:YES]];
NSError *error;
NSArray *results = [managedObjectContext executeFetchRequest:fetchRequest error:&error];
if (!result) {
// handle error
}
else {
self.ExdatasArray = [results mutableCopy];
}

NSFetchRequest canot fetch entity present in context

I have a problem where I am inserting entities A in a context. Right after I insert all of the entities A I execute a fetch request on the context:
NSEntityDescription* entity = [NSEntityDescription entityForName:#"A" inManagedObjectContext:ctx];
NSFetchRequest* fetchRequest = [[NSFetchRequest alloc] init];
[fetchRequest setEntity:entity];
NSError* fetchError;
NSArray* results = [ctx executeFetchRequest:fetchRequest error:&fetchError];
This code above is able to get all of them and I can see them in the NSLog...
Right after on the same context I try to fetch all entities A that have age = 5, like this:
(I assign "age" to the attirbute and a NSString #"5" to the value)
NSEntityDescription* entity = [NSEntityDescription entityForName:#"A" inManagedObjectContext:ctx];
NSFetchRequest* fetchRequest = [[NSFetchRequest alloc] init];
[fetchRequest setEntity:entity];
NSPredicate *filter = [NSPredicate predicateWithFormat:#"%K == %#",attr,value];
[fetchRequest setPredicate:filter];
NSError* fetchError;
NSArray* results = [ctx executeFetchRequest:fetchRequest error:&fetchError];
THE PROBLEM IS that even though the NSLog shows an entity A with age 5 this last fetch request returns always null! Nothing.
Any suggestions? Why fetching all of them shows entities with age 5 and filtering for age 5 only does not work right after on the same context?
Thanks
Try setting age to an instance of NSNumber initalized to 5 rather than the NSString #"5".

Resources