0
votes

I am trying to implement functionality to store data about user's friends (request friend, received friend request, accepted request). I have two tables.

First table is _User with username column.

Second table is Friends. This table is keeping track of who are friends of the user. This table has two fields:

  1. A pointer column to user table
  2. An array column called receivedRequest. In this array I keep the _User's objectId who are send request to that user.

Table _User has one to one relation with Friends table but meanwhile there is an array field keeping information of user's friend. In this array I am saving objectId of other users. I am using an array to avoid repeating rows for each friend's request.

Fist I want to know if this is a good idea or there is any alternative better that this. Actually I have extra array columns which is recived requests. Send requests. And accepted requests. All of them are array.

Second I want to know how can I write a query to go to Friends table. Find current user row. Go to friendList column. Return name of each friends whose name is in that array?

Currently I am doing this:

- (PFQuery *)queryForTable {

    //Query user's friend request
    PFQuery *query =  [PFQuery queryWithClassName:@"Friends"];
    [query whereKey:@"user" equalTo:[PFUser currentUser]];
    [query includeKey:@"receivedRequest"];
    return query;
}

This is returning only Id of the use's added my current user. I need their name from _User table.

enter image description here

2

2 Answers

2
votes

Here's what I'd do:

(1) the User class ought to be about the user's relationship with the app, a place for data that's just between the user and the app.

(2) For data that users want to share, have a Persona class that has an image, nickname, etc. Persona should contain a pointer to User and vice versa.

(3) Personae (Personas in common usage) make friend invitations and become friends.

(4) arrays of string object ids = bad, arrays of pointers = good. In fact, I can't think of a circumstance where I'd prefer a string object id over a pointer.

(5) A FriendInvitation ought to be its own object, where inviter and invitee are pointers to Persona.

(6) A friendship is a bilateral and symmetrical relationship (at least we always hope they are). A good representation for that might be a Friendship class that has an array of pointers to exactly two Persona objects.

Here are a few functions, given a data model:

Persona has a pointer to User, call it 'user', and User has a persona pointer. FriendInvitation has an inviter and invitee, both pointers to Persona. Friendship has an array of two pointers to Persona, call it friends

// get the current user's FriendInvitations
- (void)friendInvitationsWithCompletion:(void (^)(NSArray *, NSError *))completion {
    PFObject *persona = [PFUser currentUser][@"persona"];
    PFQuery *query =  [PFQuery queryWithClassName:@"FriendInvitation"];
    [query whereKey:@"invitee" equalTo:persona];
    [query includeKey:@"inviter"];
    [query findObjectsInBackgroundWithBlock:completion];
}

// get the current user's friendships
// remember, these are not the friends, but the objects that record pairings of friends.
// see the next function for the friends
- (void)friendshipsWithCompletion:(void (^)(NSArray *, NSError *))completion {
    PFObject *persona = [PFUser currentUser][@"persona"];
    PFQuery *query =  [PFQuery queryWithClassName:@"Friendship"];
    [query whereKey:@"friends" equalTo:persona];
    [query includeKey:@"friends"];
    [query findObjectsInBackgroundWithBlock:completion];
}

// get the current user's friends' personae
- (void)friendsWithCompletion:(void (^)(NSArray *, NSError *))completion {
    PFObject *persona = [PFUser currentUser][@"persona"];
    [self friendshipsWithCompletion:^(NSArray *friendships, NSError *error) {
        if (!error) {
            NSMutableArray *result = [@[] mutableCopy];
            for (PFObject *friendship in friendships) {
                NSArray *friends = friendship[@"friends"];
                NSInteger indexOfFriend = ([friends indexOfObject:persona] == 0)? 1 : 0;
                [result addObject:friends[indexOfFriend]];
            }
            completion(result, nil);
        } else {
            completion(nil, error);
        }
    }];
}

// agree to be friends with someone
- (void)becomeFriendsWith:(PFObject *)friend completion:(void (^)(BOOL, NSError *))completion {
    PFObject *persona = [PFUser currentUser][@"persona"];
    PFObject *friendship = [PFObject objectWithClassName:@"Friendship"];
    friendship[@"friends"] = @[ persona, friend ];
    [friendship saveInBackgroundWithBlock:completion];
}

// we could go on, but this should convey the basic ideas
1
votes

Friends table should not have arrays, but single IDs (actually pointers). So for every incoming request or friendship, there should be a single, separate entry on the database. So your Friends object (or for a better name, Relationship, or Friendship, but that's my personal preference of course) should roughly have following properties:

  • first (_User)
  • second (_User)
  • type (String. Possible values: 'friends' or 'request', maybe even 'blocked')

And for every accepted request, make sure you are creating two entries, one with first=user1/second=user2 and one with first=user2/second=user1. While you could technically go without making double entries, it will just complicate things in the long run, making everything harder to maintain.