What is the best practice approach to fetching CKReferences in CloudKit? - ios

In my CloudKit setup I have a Person record type and each person has a Friend attribute which is a CKReference to another Person object.
I fetch all Person CKRecords. I list these people in a table and list their friends with them. Currently I just take the CKReference and individually fetch each friend using the recordID.
This is the only way I can see to do it, but what would be best practice? Particularly as I am fetching potentially a very large number of friends. It seems counterintuitive to fetch all these objects individually.
I was wondering if there was a method much like CoreData, where you can choose to fetch related objects in the main fetch? So for example, when I fetch a Person it automatically fetched the friends too.

You could use an 'in' predicate query to fetch multiple id's. You can define a predicate like this:
NSPredicate(format: "To_ID in %#", [recordIdMe, recordIdOther])!
In your case where you see the recordIdMe and recordIdOther you should have an array of valid CKReference objects.
In CloudKit there is no functionality to automatically fetch related records.

Actually you should collect all the RecordIDs and add a CKFetchRecordsOperation to the relevant database object.
You get a back a dictionary to help you match the results with the original list.

Related

CloudKit: fetch record and references in one query (like in Parse)

With the impending death of Parse, I'm re-writing an app using CloudKit. Suppose I'm making a recipe scheduling app. I want a given schedule to contain an ordered list of recipes, and recipes can be in multiple schedules. So I have:
a Schedule object, which has a one-to-many relationship to ScheduleItem objects called "scheduleItems"
a ScheduleItem object has a dayOfWeek field and a one-to-one relationship with a Recipe object called "recipe"
a Recipe object has some information, including its name and ingredients (more relationships)
Assume I have the Schedule object, and I want to get all of its ScheduleItems AND their associated Recipes in one single query. In Parse, I could set up this query:
PFQuery *query = [PFQuery queryWithClassName:#"Schedule"];
[query includeKey:#"scheduleItems.recipe"];
And that query would fetch all the scheduleItems along with all their recipes, allowing me to avoid having to perform multiple network requests.
Is there a way to do this in CloudKit? I see that I can use a CKFetchRecordsOperation to fetch multiple records at once given their recordIDs, but I wouldn't know the record IDs of the recipes until I had already fetched the scheduleItems, thus still necessitating a second network request.
CloudKit is not a relational database. It's a key-value store. There is no functionality to query multiple recordType's in one query. There is also no functionality for aggregation queries. In your case since it's a one to one relationship you could limit it to 2 queries by adding a CKReference in your Recipe to the Schedule. So then if you have a schedule, you could do one query to get all related ScheduleItem's and an other query to get all related Recipe's
There is a way in the coming version ('16): you can define parent relations and then fetching the parent records will result in the children being fetched as well. This is covered in the WWDC session 'What's New in CloudKit' (2016): https://developer.apple.com/videos/play/wwdc2016/226/
Correction, the parent reference introduced in '16 is not to make it possible to do a single fetch, but rather to automatically share all descendants, when using the new Sharing part of the API. So the answer is no there is still no way but when sharing records, it is a bit less onerous.

Check if PFObject is in PFRelation

I am building an iOS in Swift using Parse.com as my backend.
I have a table of objects: car, and each car can be owned by multiple users, so I have a Car table with the column owners which is a PRRelation of the _User table.
I am displaying all the cars in a TableView and want to determine (for each object) whether the PFUser.currentUser() is in the Relation of _User objects for each car.
Is there a way of doing this without creating a query which then makes a request to the Parse server? Doing that seems very inefficient to have to check again for each object, and would make a large number of Parse database calls which would make me hit the call limit quite quickly if multiple people are using the app...
So is there a way to simply do something like:
if carObject["owners].contains(PFUser.currentUser()) {
println("the current user is an owner of this car")
}
Might it be possible to run a query of all cars, and then another query of all the cars with a whereKey restriction on the students column and then comparing queries? How could I compare the queries?
Have you created your car class in your app? You can download all your car objects from parse at once, put them in an [Car] and then you'll have all the relational data as well.
I'm not 100% sure but you may need to use parsequery.includeKey("users") when you query parse so it also includes the parse user. User's being an attribute of Car.

Core Data: NSFetchedResultsController sorting by date vs. ordered to-many relationship

I am writing a demo messaging app to learn Core Data. In my model, an entity Conversation has a to-many relationship messages to Message. A Message has a timeStamp. I intend to display these messages in a collection view/table view with an NSFetchedResultsController. I want to know what would be the most efficient way to sort these messages. I searched around and found that I could sort the messages using:
an NSSortDescriptor on message.timeStamp
making the messages relationship ordered
adding a sequence property to message
What should be the best way to sort the messages?
The sort order should reflect your application logic:
is it logical to move messages inside a conversation? (if yes, sort by sequence number)
Do you want your data to be displayed chronologically? (if yes, sort by timeStamp)
in any case I wouldn't use the ordered relationship as a sort order as you would probably want an FRC to display your data in a table view, and he will manage memory and changes for you.
In addition to that you would want to batch fetch this relationship in any case and not simply let your table view datasource be the ordered set relationship (which will cause the items to be fetch one by one).

Difference between Fetch Requests (model templates) and Fetched Properties in Core Data

What's the difference between them? Both need predicate. I've used them both but I can't understand the difference. Thanks! (I think it doesn't matter, but I'm working in iOS, Xcode 4 last version).
A fetched property is kind of a relationship. It's not a direct, two-way relationship, it's a one-way relationship. So only one one object knows about the relationship. The fetched property is (normally) described by a predicate and uses a fetch request to retrieve the objects.
A fetch request retrieves objects from core-data. The actual instances of an entity. It doesn't need a predicate if you don't need to filter the objects.
same:all cached query method;
difference:
Fetch Requests-->really Fetch Requests;just fetch something from a single table
Fetched Properties --> fetch something from different table based on data from this table;like use :select from table2 where id = thisrow.id

How do I create a core data entry with a queryable array property?

I have two entities, Issue and User, which I'm using to represent data that comes to me from a server. There's a many-to-many relationship between Issues and Users, and when I get an Issue from the server the object has an array of User IDs.
Later, when I get a User from the server, I want to be able to find the issues that I've stored that have a matching ID.
I had been planning to use a transformable property to store the User IDs for each Issue. However, I've read that transformable properties aren't queryable. Is that true? If so, how do I create an array property that is queryable?
It is correct that you cannot query for entries in an array that is stored as a transformable attribute of the entity.
One possible solution would be to store the list of users IDs as a comma-separated string attribute in the Issue entity, and later search for a matching ID as described here:
Form NSPredicate from string that contains id's.
A different solution would be to create the relationships from Issue to User already in the first pass, when reading and creating the issues. When you get an issue from the server with a list of user IDs, you would find or create the User objects and set the relationship.
Since you are using two entities with many-to-many relationship why don't you implement the relationship using core-data? i.e The usersSet (say) in Issue entity will be an NSSet and the issuesSet in User will be also an NSSet. If thats the case you could implement a predicate in the below way to easily get what you want:
(The below code assumes the to-many relationship between Issue to User is usersSet.)
User *userObjFromServer = <your user object from server>...
NSString *userId = userObjFromServer.userId; //Whichever way you are doing this
NSPredicate *predicate = [NSPredicate predicateWithFormat:#"ANY usersSet.userId like %#",userId];
The queryable array you are talking about will be the relationship (only, its an NSSet).

Resources