简体   繁体   中英

Search by Mutual Friends Count - Friend System Mysql PHP

I am creating a Friend System in my Forum.

I am having a tough time trying to figure out how I would grab users and order by the mutual_friend count.

I am trying to build a page that shows a list of recommended friends.

Here is my structure of tables:

users table
-----
user_id | name |

friends table
-----
friend_id | from_id | to_id

Here is an example of what is happening.

Suppose there are total of A , B , C , D , E , F = 6 people in the site.

  • I am A , and B , C are my friends.
  • D and E in turn are friends of B .
  • D is also a friend of C but E is not a friend of C .
  • F is not a friend of anyone in the site.

Therefore from above data it looks like D and E are mutual friends of me ( A ). F is not a mutual friend of mine.

Since D is a friend of both B and C and E is friend of only B :

  • A and D has 2 mutual friends.
  • A and E has 1 mutual friend.
  • A and F has 0 mutual friend.

Now if I want to search (remember i am A ) for people who are not my friends I can do something like:

$myfriends = "2,3"; //putting all my friends in a variable

SELECT * FROM users WHERE user_id NOT IN( $myfriends )

But it will yield in terms of user_id ASC .

How can I make it search in DESC order of mutual_friends . ?

I am A ie user_id = 1

ie Person with more mutual friends comes first

Please can anyone show me how can I do this? I have been stuck here for a long while. I searched for lots of thing but can't figure it out.

This query will take the reciprocity of relationships into account, so it doesn't matter if the relationship goes "From A to B" or "From B to A", it will still return the expected result. So given tables like this:

CREATE TABLE people
    (`id` int, `name` varchar(1))
;

INSERT INTO people
    (`id`, `name`)
VALUES
    (1, 'A'),
    (2, 'B'),
    (3, 'C'),
    (4, 'D'),
    (5, 'E'),
    (6, 'F')
;


CREATE TABLE friends
    (`id` int, `personId1` int, `personId2` int)
;

INSERT INTO friends
    (`id`, `personId1`, `personId2`)
VALUES
    (1, 1, 2),
    (2, 3, 1),
    (3, 2, 4),
    (4, 5, 2),
    (5, 3, 4)
;

I believe this is set up as you described: A and B are friends, A and C are friends (notice the inverted relationship), B and D are friends, E and B are friends (another inverted relationship), and C and D are friends.

Assume the id of the person you want is in @personId:

SELECT StrangerId, COUNT(MutualFriendId) AS TotalMutualFriends
FROM
(SELECT
  CASE WHEN f.personId2 = mf.friendId THEN f.personId1 ELSE f.personId2 END AS StrangerId,
  CASE WHEN f.personId1 = mf.friendId THEN f.personId1 ELSE f.personId2 END AS MutualFriendId
FROM
(SELECT 
  CASE 
    WHEN personId1 = @personId THEN personId2 
    ELSE personId1 
  END AS friendId 
FROM friends 
WHERE personId1 = @personId OR personId2 = @personId) AS mf
INNER JOIN friends f
ON (personId1 != @personId AND personId2 = mf.friendId) 
  OR (personId1 = mf.friendId AND personId2 != @personId)
 ) AS totals
 GROUP BY StrangerId
 ORDER BY TotalMutualFriends DESC;

Results for @personId = 1 are:

StrangerId  TotalMutualFriends
4           2
5           1

And here is a SQLFiddle to demonstrate (I couldn't get it to allow me to set up a variable, so there is a 1 in its place).

Something like this, perhaps:

Select user_id, friends.to_id, count(friend_of_friend.to_id)
from users left outer join
    friends on users.user_id = friends.from_id left outer join
    users as friend_user on friends.to_id = friend_user.user_id left outer  join
    friends as friend_of_friend on friend_user.user_id =    friend_of_friend.from_id and friend_of_friend.to_id in (select to_id from friends where from_id = users.user_id)
Group by USER_ID, friends.to_id
Order by 3

Edit for clarity: The logic of this query depends on joining the same table multiple times. The first two joins are pretty straight-forward, we are starting with a table of users, then joining in the friends table that links each user with all their friends. But then we join in the user table again, but this time using the "to" column - we are getting the user info for each friend. Since we can't have the same table name twice in a query, we give it an alias of "friend_user". Then we join the friends table again, based on the id in the friend_user table - this gives us all the friends of each original user's friends. Then we limit the friends of friends that we get back using the "Friend_of_friend.to_id in ..." to compare the friends of friends to a list of all of the original user's friends, which we bring in by a subquery - the section just after the "in" that is enclosed in parenthesis.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM