11

I am using Parse as my backend. I have problems setting up the correct relation between objects.

I basically have a class named Post, each post belongs to a user(PFUser), and when fetching a post I want the user info to be fetched along with the post.

@interface Post : PFObject<PFSubclassing>

@property (nonatomic, strong) NSDate *time;
@property (nonatomic, strong) NSString *title;
@property (nonatomic, strong) NSString *body;
@property (nonatomic, strong, readonly) PFRelation *user;
// User in backed is defined as a relationship to _user    

@end

// Saving the post
[post.user addObject:[PFUser currentUser];
[post saveInBackground];

This works fine and relates the post to that user, but when I try to fetch the post later, it doesn't seem like I can get an instance of _user from PFRelation.

What is the correct way to handle this? Tried to change PFRelation to PFUser but that would crash because it tries to call save on the PFUser object

aryaxt
  • 76,198
  • 92
  • 293
  • 442

4 Answers4

31

A Relation is for when you want a long list of related classes, where an array doesn't work, or when you want to query the related objects as needed and not have the list included every time you load the containing object.

Basically you have 4 options with Parse:

  • Pointer - single reference to another class (1 to 0..1)
  • Array - collection of pointers, loaded with the object every time (1 to 0..n, small lists)
  • Relation - collection of pointers, like a join table in SQL (handled under the covers for you), you must run a query against it to load values (1 to 0..n)
  • Custom join class - really just another object (like many-to-many join in SQL) with a Pointer to each side plus any related information (1..n to 1..n)

In your case a simple Pointer would do what you want.

Timothy Walters
  • 16,866
  • 2
  • 41
  • 49
  • Thanks, great answer. Is it possible to perform a query and get a count? Or somehow add a navigation property on a PFObject that would give you a count? Let's say get a Post object that also includes number of comments related to it? – aryaxt May 04 '14 at 21:42
  • 2
    @aryaxt The comment count for a Post is actually something that is covered in the documentation. While you can use a `countObjects` query it is easier to have some Cloud Code that after-save of the Comment increases a counter (using `incrementKey`) on the Post. – Timothy Walters May 05 '14 at 20:10
3

In your usecase, a pointer is preferable over a PFRelation. You can include the user info by adding includeKey in your query:

[query includeKey:@"user"];

A way to get a comment count on your post is to add every new comment to an array of pointers in your Post.

It is easy to get stuck in the old SQLish ways when you start using NoSQL databases. If a counter is desirable, you could add a cloud code afterSave function on the comment object that updates the "comments" column of the Post class by adding a pointer to the saved comment to the "comments" array in Post. This way, when you fetch a post you can also use

[query includeKey:@"comments"];

which will give you the Post AND all the comments in one query. If you only need the count, you ommit the includeKey, but you still have an array in "comments" with the pointers, so the comment count is the length of the array.

Marius Waldal
  • 9,537
  • 4
  • 30
  • 44
2

You must create a query from the PFRelation object, like in this code snippet (taken from Parse documentation) and do an explicit query to retrieve the referenced object:

[[relation query] findObjectsInBackgroundWithBlock:^(NSArray *objects, NSError *error) { if (error) { // There was an error } else { // user(s) } }];

Parse provides the possibility to retrieve also referenced objects in the original query, and this is done using the "includeKey:" method in the original query (that is the query you setup to get the posts), by asking to return the user data and not just the reference. But I'm not sure if it works for PFRelation as in the documentation it is stated that includeKey works for PFObject and PFRelation is not a PFObject. You may try this code in any case and see if it works or not:

[query includeKey:@"user"]

viggio24
  • 12,316
  • 5
  • 41
  • 34
  • Thanks for the response. I just solved this problem by using a pointer rather than a relationship, and changing my property type to PFUser. Before I had it set to a relationship, and it was trying to update the PFUser. I think that's why it was throwing an exception – aryaxt May 04 '14 at 17:32
  • Do you think my approach is better? If not why,and how do you decide between pointers and relationship? – aryaxt May 04 '14 at 17:33
  • I also use the direct class approach, that is without using PFRelation. According to Parse documentation, PFRelation is well suited for N-to-M relations. The example they do is that in a social app each user may like multiple posts and each post may be liked by multiple users. So in your case as you link the post to the user (and not viceversa) you can use the direct class-based reference. But if you want to build the inverse relationship, which is 1-many (1 post, many users that like it) in such case it is much better to use the PFRelation instead of a NSArray – viggio24 May 05 '14 at 09:19
0

Create A PFSubClass like

yourClassName:PFObject with PFSubclassing 

and then in the header file create a Pointer relation

@property(nonatomic, strong) PFUser *userLikeRelation; 

add in m file add

+ (NSString *)parseClassName {

    return @"parseTableName";

}

+ (void)load {

    [self registerSubclass];

} 

finally in the View Controller set relation in query when you are save data in parse.

yourClassName *yourClassNameObj = [yourClassName objectWithClassName:[yourClassName parseClassName]];

[yourClassName setUserCommentRelation:[PFUser currentUser]];

for fetching data you can get data with include key

[yourClassNameObj includeKey:@"NameofRelation"];
Noah Passalacqua
  • 792
  • 2
  • 8
  • 24
Ashok Kumar
  • 225
  • 4
  • 9