Understanding and using Parse many to many relations - ios

I have 2 tables in Parse like so:
Users:
(PFUsers table with all Parse data)
belongsToGroups (A Parse Relation to Groups which is many to many)
Groups:
groupId
name
groupMembers (A Parse Relation to Users which is also many to many)
I have the following code:
PFObject *groups = [PFObject objectWithClassName:#"Groups"];
groups[#"name"] = name;
syncUsers[#"isActive"] = [NSNumber numberWithInt:1];
//[groups saveInBackground];
PFUser *current = [PFUser currentUser];
PFRelation *relation = [syncUsers relationforKey:#"groupMembers"];
[relation addObject:current];
[groups saveEventually];
PFRelation *relation2 = [current relationforKey:#"belongsToGroups"];
[relation2 addObject:groups];
[current saveEventually];
First, the top 2 blocks of code work fine, but how do I update the relationship in Users so that I can do View Relation in Parse and see my groups?
Two, do I need to create the Relation in users AND groups so that it can be many to many?

You can use whereKey:equalTo: on a relation column and pass it a PFObject. This query will then return all Teacher objects which have this student in their "students" relation:
PFQuery *query = [PFQuery queryWithClassName:#"Teacher"];
[query whereKey:#"students" equalTo:student];
In this example, the student is a PFObject with a className that matches the relation in "students". If this is a relation of PFUsers and you're looking for the current user's "Teacher"s, you'd use:
PFQuery *query = [PFQuery queryWithClassName:#"Teacher"];
[query whereKey:#"students" equalTo:[PFUser currentUser]];

First for a relation you need that both objects exist in the Parse Database. Then you must use the PFRelation object and save the object with the relation.
I recommend using CodeCloud for stablishing relationships so you can share the code with Android or Web Apps.
// Objects
PFObject *student = [PFObject objectWithoutDataWithClassName:#"Student" objectId:#"xauj37H"];
PFObject *teacher = [PFObject objectWithoutDataWithClassName:#"Teacher" objectId:#"xJdcj238"];
// Add a student to the teacher object
// Get the students relation
PFRelation *studentsForTeacher = [teacher relationForKey:#"students"];
// Add a student
[studentsForTeacher addObject:student];
// save the teacher, use InBackground instead
[teacher save];
// Now add a teacher for the student
PFRelation *teachersForStudent = [student relationForKey:#"teachers"];
[teachersForStudent addObject:teacher];
// Save the student
[student save];
// And now you can query the students of a teacher or the teachers of a student
// Students for a Teacher
PFQuery *studentsQuery = [studentsForTeacher query];
[studentsQuery find];
// Teachers for a Student
PFQuery *teachersQuery = [teachersForStudent query];
[teachersQuery find];

Related

How do I fetch all relation objects in Parse.com IOS?

I have the following query:
PFObject *photoData = [PFObject objectWithClassName:#"Photos"];
PFRelation *relation = [photoData relationForKey:#"photo"];
PFQuery *query = [PFQuery queryWithClassName:#"People"];
query = [relation query];
[query whereKey:#"deleted" equalTo:#NO];
[query whereKey:#"createdAt" lessThan:_createdAt];
[query orderByDescending:#"createdAt"];
query.limit = 20;
[query findObjectsInBackgroundWithBlock:^(NSArray *objects, NSError *error) {
...
}
I have a database table in Parse called People. In that table, there is a bunch of data but has a relation called photo. Now, I am saving one photo (with its data) in the photo relation. In the Parse dashboard, the data is saved correctly.
How do I fetch that back? Right now I have constraints on this system (and question) that each People objects has ONLY one photo object. So I need to fetch it all back at once.
Relation is just what its literal meaning is. It does not contain any data. If you want to query the data, you need to get the PFQuery from PFRelation by query method like so:
PFRelation *relation = [photoData relationForKey:#"photo"];
PFQuery *photoQuery = [relation query];
// perform your photoQuery here
If you limit them by one object only, then you can change your photo as Pointer type instead of using Relation.

Start query from relation

I have a class named Circle with a relation named "members" to the _User class.
Class Circle:
Class _User:
I'm trying to query all Circles that the current user belongs to (inside the "members" relations).
PFUser *user = [PFUser currentUser];
PFRelation *relation = [user relationForKey:#"members"];
PFQuery *query = [relation query];
[query findObjectsInBackgroundWithBlock:^(NSArray *PF_NULLABLE_S objects, NSError *PF_NULLABLE_S error){
//objects size here is 0
//error is nil
}];
The problem is that the NSArray is empty and no error is received into the block.
One solution I'm thinking of is creating an actual table to store this relation and have a Relation column in both Circle and _User, but I believe there should be a better way to do this.
It doesn't appear that user has a members col. So, asking a user for its members relation is sure to fail. You want to query Circle...
PFQuery *query = [PFQuery queryWithClassName:#"Circle"];
[query whereKey:#"members" equalTo:user];

parse web service relational database

I am using parse to develop an iOS app.
For the database, I have three tables, named user, UserAndCourse, and course.
Where UserAndCar stores a pointer to user and course.
the tables looks like:
My problem is:
How can I query the courses that belongs to the current user on iOS. i.e that look into UserAndCourse to find the rows that user column is current user and query for the course object that is pointed to by the course column.
Can I do this in a single relational query? or I have to query the UserAndCourse table rows first and then query the course it pointed to.
I suggest to use PFRelation, that way you don't need to create new table for relations like userAndCourse. Parse automatically will link through the relation. You just need to create relation between them and do what you want.
Saving relation;
PFUser *user = [PFUser currentUser];
PFRelation *relation = [user relationForKey:#"course"];
[relation addObject:coursePFObject];
[user saveInBackground];
And query when you need to reach them;
PFRelation *relation = [user relationForKey:#"course"];
PFQuery *query = [relation query];
[query findObjectsInBackgroundWithBlock:^(NSArray *results, NSError *error) {
// results contains all the people who subscribe to course
}];
Moreover you can specify your course by adding more queries on it;
PFQuery *query = [relation query];
[query whereKey:#"name" equalTo:#"Math"];
[query findObjectsInBackgroundWithBlock:^(NSArray *results, NSError *error) {
// results contains all the people who subscribe Math course
}];
I think it's better way to shape your tables in parse. Otherwise you need to create table for each relation.
Hope it helps also if you need more detail this can be helpful.

Adding constraints to a PFQuery with objects from a PFRelation

I am using a PFQueryTableViewController and I am querying PFObjects called Group. These groups objects all have relations to a User PFObject. I want to add constraints to this query by querying only the groups that have relations containing the current user. How do I add constraints to a query by only returning objects that contain the current user in the relation?
-(PFQuery *)queryForTable{
PFQuery * query = [PFQuery queryWithClassName:#"Group"];
//Users is a relation
[query whereKey:#"Users" equalTo:[PFUser currentUser]];
//This crashes the app
//I need to return only objects with current user in the users relation
return query;
}
Thanks

Parse iOS how query object by properties found in related PFObject?

I am writing an iOS app and I am using Parse to store data on the server side.
I have Users and each user can have a Car.
I am trying to figure out how to write a query that allows me to get all users that have a car with year less than 2000 and with a certain color (lets say red).
Each car has a relationship to the user and each user also has a relationship to their car.
User <-> Car (one to one)
I started using the PFQuery:
PFQuery * userQuery = [PFQuery queryWithClassName:#"User"];
I am not sure how to handle the relationship in the query. So, I'm pretty much not sure how to get this done.
Any suggestion?
First off, the User class is a special case, when using it in a query you need to do this:
PFQuery *query = [PFUser query];
Next, the way you construct the query you want depends where the pointer is. If the User has a car property that is a pointer to the Car then the query would be as follows:
PFQuery *userQuery = [PFUser query];
PFQuery *carQuery = [PFQuery queryWithClassName:#"Car"];
[carQuery whereKey:#"year" lessThan:#(2000)];
[carQuery whereKey:#"color" equalTo:#"red"];
[userQuery whereKey:#"car" matchesQuery:carQuery];
[userQuery includeKey:#"car"]
[userQuery findObjectsInBackgroundWithBlock:^(NSArray *users, NSError *error) {
for (PFObject *user in users) {
PFObject *car = user[#"car"];
// read user/car properties as needed
}
}];
If instead the Car class has a user property you just do a normal query and add the following line to let you access the full User object:
[carQuery includeKey:#"user"];
What does your table look like? If you have User as a column in your Car table, you can just query the car table for cars of year less than 2000 and then you would just access the User property of that query. It would look something like this:
PFQuery *carQuery = [PFQuery queryWithClassName:#"Car"];
[carQuery whereKey:#"year" lessThan:#(2000)];
[carQuery includeKey:#"user"];
[carQuery findObjectsInBackgroundWithBlock:^(NSArray *cars, NSError *error) {
if (!error) {
for (Car *car in cars) {
User *user = car#["user"];
}
}
}];

Resources