NSPredicate traversing relationship (StackMob) - ios

I have been scouring Apple's Predicate Programming Guide and SO as well, trying to determine the correct way to write a predicate for a certain fetch request.
It seems like the way I am attempting to use dot notation to traverse a relationship is not being respected by the request.
NSEntityDescription *entity = [NSEntityDescription entityForName:#"Task" inManagedObjectContext:context];
[fetchRequest setEntity:entity];
NSPredicate *predicate = [NSPredicate predicateWithFormat:#"project.user == %#", self.user];
[fetchRequest setPredicate:predicate];
User, Project, and Task are all core data entities mapping to a BaaS provider (StackMob).
Relationships are as follows: User one-to-many Project one-to-many Task with inverse relationships as you would expect. What I am trying to do is get all tasks for the current logged in user. So, my thinking is: send a fetch request with the entity "Task". Where the project that owns the task is owned by the logged in user, get that task and display it. Simple enough.
And I think I should be able to use the dot notation in the predicate that I have shown above, but the fetch request is returning nil.
Everything else about the fetch request is fine. If I change the format string to #"project != NULL", I get all of the tasks back.
Am I just writing my format string incorrectly? Is dot notation somehow not valid when sending a fetch request to StackMob?
As always, any help is greatly appreciated.
Please let me know if more information is needed. I'm a little too close to this right now to see it clearly.

Fetching on an attribute of a relationship (task where project.user == X) is not supported by StackMob. However, it looks like you are trying to get all the tasks for a given project for the logged in user. If I am correct in assuming that the logged in user was the one to create the projects and tasks, then set the permissions of the project schema to "Allow to sm_owner". You can then fetch tasks based on the project ID (task where project IN 1234), or project based on ID and grab all tasks (project where projectId == 1234 and use value of tasks relationship). Either way, with that permission fetches will only return results where sm_owner == logged in user, so you don't need to set up the fetch such that it uses the user ID as a filter. Hope that helps!

Related

How to save data against each user core Data

I am trying to my data set to Core data. I could successfully save the data in coreData.
mY application have login. So, I need to save data against each user.
Now I visible the whole data foe every user.
Is there any idea for save user specific.
This is a job for your business logic.
One one hand, I suspect you have data that is available for everyone, you do not need to protect these.
For entities where the access should be restricted, you can store information about valid users or user groups in an attribute or a relationship. If you want to display a list of entities of that kind to the user, you have to fetch the data with some NSPredicate which gets you only the entities of the user, like so:
predicate = [NSPredicate predicateWithFormat:#"(user = %#) and (exampleAttr = 42)", currentUser];

Query table based on a value in FK

I have a couple of tables:
User:
- userId (NString)
- name (NSString)
Report:
- reportName (NSString)
- user (foreign key to user table)
I have a userId and I want to get all reports for that user. Do I have to query for the user first from core data?
If so this is bad as I am trying to implement find and update logic as outline by apple. In my case I only have one report per user. I am getting back an array of reports from the server and each report contains a userId (assigned by server). If I don't have a report for that user yet I need to create one. If I have report for that user I need to update with the new report.
So basically I create an array of NSString (userId's) to use in a predicate:
NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init];
[fetchRequest setEntity:[NSEntityDescription entityForName:#"Report" inManagedObjectContext:context]];
[fetchRequest setPredicate: [NSPredicate predicateWithFormat:#"(userId IN %#)", userIds]];
However in this case userId does not really exist, user is a foreign relationship.
I could not make a foreign relationship and just store userId in report but then I need to manually join later. Is that a better option.
The notion of a foreign key does not exist in Core Data. Sure, they're used for one of the possible backing stores, but the foreign key is hidden. In its place, we have instead a relationship.
If you have a relationship established, you just walk the keypath. No further fetch is necessary.
You need inverses for your relationships. So if a Report has a User, the User has Reports.
For your purposes, I suggest implementing a reportWithReportName: (does a fetch), findOrCreateWithReportName: (tries a fetch, does an insert if necessary), userWithUserID: (does a fetch), and findOrCreateUserWithUserID:name: (fetch, insert if needed).
Report *aReport;
User *someUser;
NSLog(#"%#", aReport.user.name, aReport.user.userID);
NSLog (#"%#", someUser.userID, someUser.reports);
foreach (Report *report in someUser.reports) {
NSLog(#"%#", report.reportName);
}

Core Data, iCloud and Pre-Built Data with iOS 7

I'm a in a really common situation mostly driven by inexperience...
My application inserts pre-built data in the DB at the first launch.
I just check for db existence in the device... if it doesn't exist this is the first launch so I add my pre-built data after DB creation.
At the end of the development I decide to activate iCloud, wow! just one row of code to make it works... I tried it on different devices and my pre-built data were obviously duplicated :(
I understood that the better way to manage pre-built data is to work with more than one persistent store, creating read-only store for pre-built data (my pre-built data don't need to be modified by the user, so the read-only solution would be ok).
The problem is that I have relationship between data inserted by user so I can't work on multiple persistent store (core-data doesn't support relation between different stores).
I took a look at Fetched Properties but it seems to require a super drastic edit on my code.
I thought to go with de-duplicating data... so just removing data that are already in the DB, my doubt is that this process is really dangerous for relationship, how can I delete the object that is just a duplicate of the "original" created at the first launch?=
Given that my pre-build data are can't be modified or deleted by the users, which is in your opinion the best way to correct this problem?
// EDIT: Some information about the model:
The entity that users are dealing with (add/edit/modify)represents a TASK.
this entities have a name, and a CATEGORY.
CATEGORY are the entities that I pre-build.
So user add a name for the task and select a CATEGORY from the pre-built data.
In your Category entity, in the PrebuiltData model, create an "id" property (and make sure that this is consistent from version to version) This model should not be managed by iCloud.
In your Task entity, in the UserData model, create a "categoryId" property. This model should be managed by iCloud (or this discussion is meaningless)
Now you can create a method on your Category entity to fetch all the Tasks in the category using:
-(NSArray*)tasks
{
NSFetchRequest* request = [NSFetchRequest fetchRequestWithEntityName:#"Task"];
request.predicate = [NSPredicate predicateWithFormat:#"id = %#", self.id];
return [gTaskManagedObjectContext executeFetchRequest:request error:NULL];
}
Likewise, you can create a method on your Task entity to fetch the category:
-(Category*)category
{
NSFetchRequest* request = [NSFetchRequest fetchRequestWithEntityName:#"Category"];
request.predicate = [NSPredicate predicateWithFormat:#"id = %#", self.categoryId];
NSArray* results = [gTaskManagedObjectContext executeFetchRequest:request error:NULL];
return results.count > 0 ? results[0] : nil;
}

Predicate for NSFetchRequest Core Data based on content in other entity list

I have the following Core Data Model:
User has attributes username(string) and user_id(integer).
ContactStatus has first_user_id(integer), second_user_id(integer), and status(string which is either "1REQ","2REQ", or "CONF").
I want to get a list of contacts for a given user with a user_id of u_id, the equivalent SQL would be:
SELECT first_user_id,second_user_id FROM ContactStatuses WHERE (first_user_id == u_id OR second_user_id == u_id) AND status == 'CONF'
Or is there a better way to organize my data in Core Data? This is the way its organized in my MySQL database.
Edit:
I have a MySQL database on my server, and in php/sql, if I wanted to return a list of a user's contacts, I would use the above query. As I download this information (in JSON) to my iOS app, I would like to store these users' information in the managed object context. Then, when I want to display a list of contacts to the users, I would want to query the managed object context with a fetch request similar to the above SQL statement. The problem is that I don't know how to filter users with a predicate that comes from a different entity, the contactstatus entity.
CoreData is an object graph representation of your data, in most cases it is backed up by an SQLite database.
I assume that you need to sync your objects with a server side database and so you must define your own user_id property.
However, it might make sense for you to make a relationship between a User entity and a ContactStatus entity (this depend on your implementation and application needs that you have not listed).
In any case, under your current implementation (assuming your query target entity is ContactStatus).
Your predicate should look something like:
[NSPredicate predicateWithFormat:#"(first_user_id = %# OR second_user_id) AND status = %#",#(u_id),#(u_id),#"CONF"];

Modelling short-term objects in Core Data app

I have an app that talks to the server to get some items (Item class) for current user and store it. So far so good.
I want to implement search, that essentially returns me a set of Item objects, but obviously I do not want to persist every search result there ever be. Another use case is that server API has different endpoints like recommendations/ new/ upcoming/ that return the same Item object, but in different context, so I would like to differentiate between them somehow.
My first thought was to use a throw-away managed context, load objects from API in there, do fetch and when user is done just destroy the context. Is it a good idea in general? It saves code, because most of my VCs already talk to core data.
Rather than throwing the whole wonderful infrastructure of Core Data away, you should leverage it to achieve your purpose.
Add a timestamp attribute to your entity and use it to selectively display search results or even purge your store from old items.
Add a category attribute to your entity and filter by category when searching.
Both can be achieved with an NSPredicate that you add to your NSFetchRequest. For example:
fetchRequest.predicate = [NSPredicate predicateWithFormat:
#"timestamp > %#", [[NSDate date] dateByAddingTimeInterval:numberOfSeconds]];
or
fetchRequest.predicate = [NSPredicate predicateWithFormat:
#"category = %#", #"new"];

Resources