Skip to content

A More Scalable Many-to-Many Approach

In a previous blog post, we highlighted our support for many-to-many relationships. In the past week, we've improved our handling of large many-to-many relationships, which was cumbersome with the simple array of PFObject approach. Now you can use the PFRelation primitive to deal with large many-to-many relations. The same scenario of keeping tracking of people who like a restaurant would look like:

// Let's say people is an NSArray of "Person" PFObjects.
PFObject *place = [PFObject objectWithClassName:@"Place"];
[place setObject:@"Sid's BBQ" forKey:@"name"];
PFRelation *relation = [place relationForKey:@"likes"];
for (PFObject *person in people) {
  [relation add:person];
}
[place saveInBackground];

When you fetch the Place object, the objects in the relations won't be fetched, which is a huge win for a relationship with a large number of objects. Even without fetching all the objects in the relation, you can add objects to the relation using add:. If you wanted to fetch all the objects in the relations, you would do something like:

PFRelation *relation = [place relationForKey:@"likes"];
PFQuery *query = [relation query];
[query findObjectsInBackgroundWithBlock:^(NSArray *results, NSError *error) {
    // results contains all the people who liked Sid's BBQ.
}];

If you only wanted to fetch a subset of the people who liked a Place, you can add other query constraints to the query that was returned by the relation.

PFQuery *query = [relation query];
[query whereKey:@"location" equalTo:@"Savannah"];
[query findObjectsInBackgroundWithBlock:^(NSArray *results, NSError *error) {
     // results contains all the people who liked Sid's BBQ who are in Savannah
}];

You can still do all the queries on the Places Class that you could do before with arrays of PFObject such as:

PFObject *personNamedBob = ...;
PFQuery *query = [PFQuery queryWithClassName:@"Place"];
[query whereKey:@"likes" equalTo:personNamedBob];
[query findObjectsInBackgroundWithBlock:^(NSArray *results, NSError *error) {
    // results contains all the places liked by Bob.
}];
// Create a query for People in Australia
PFQuery *query1 = [PFQuery queryWithClassName:@"Person"];
[query1 whereKey:@"location" equalTo:@"Australia"];

// Create a query for Places liked by People in Australia.
PFQuery *query2 = [PFQuery queryWithClassName:@"Place"];
[query2 whereKey:@"likes" matchesQuery:query1];
[query2 findObjectsInBackgroundWithBlock:^(NSArray *results, NSError*error) {
   // results contains the places that are liked by people from Australia
}];

For more information about PFRelation please take a look the Relation Section of the iOS Guide. Android developers can look at the Relation Section of the Android Guide for information and examples for Android.