Php mysql мои друзья

Как реализовать хранение друзей в БД?

Как хранить связи вида пользователь-друг — понятно. Создаем таблицу friend в которой два столбца — user и friend. Делаем ключ по двум полям. Соответственно, пользователь А, добавил в друзья пользователя B — появилась соответствующая запись. Когда пользователь В подтвердил заявку в друзья — создается симметричная запись.

Далее, если хотим вывести друзей пользователя, пишем что-то вроде
select f1.friend from friends f1 join friends f2 on f1.user=f2.friend and f2.user=f1.friend where f1.user=:user_id

Но что делать если мы хотим вывести не только т.н «взаимных друзей» но и заявки в друзья и не подтвержденные заявки в друзья.
т.е например:
Пользователь user1 добавил в друзья пользователей user2, user3. user2 подтвердил заявку. user4 добавил в друзья user1. И в профиле user1 должно выводиться:
user2 (удалить из друзей)
user3 (отозвать заявку)
user4 (принять заявку)

Как правильно написать запрос? Или одним запросом не обойтись?

А что если хранить немного по другому?

Например не создавать дублирующую запись в обратную сторону, а изначально использовать еще одно поле в троичной системе счисления: ± 1 когда один пользователь добавил другого (знак указывает направление заявки) и 0 когда заявка подтверждена.

Тогда запрос будет один на выборку пары, а состояния отозвать/принять заявку и удалить из друзей будут определяться знаком числа в дополнительном поле.

Из очевидных плюсов. Места занимать будет примерно в два раза меньше — мелочь, а приятно.
Минусов не сразу не соображу.

При нажатии на кнопку отозвать/принять заявку и удалить из друзей — не удаляется запись, а просто меняется значение поля, что, на мой взгляд, намного лучше постоянного добавления/удаления записей (знатоки БД — поправьте, если я не прав).

Просто тогда непонятно как выбирать друзей пользователя. Если делать что-то вроде select * from friend where user = :user_id or friend = :user_id, то не совсем понятно становится, кто кого добавил friend юзера в друзья или юзер френда. Ну и соответственно запись вида

будет означать одно и то же. Понятно, что добавляться будет только одна из них, но мороки, имхо, слишком много

Записи не идентичны.
если 1 добавил 2, то будет запись 1 2 0
если 2 добавил 1, то будет запись 2 1 0

Тут по записи видно кто инициировал добавление, кроме того, можно даже для дополнительного поля использовать bool, характеризующий подтвержденность дружбы. А направление запроса брать из полей user и friend.

Все что выше — мое видение направления решения. Идти в этом направлении или нет — решать вам.

Добавить ещё одну колонку — тип связи. Будет — user, friend, relation_type, где relation_type, например, friend/not_approved_friend/declined_friend/follower. А в выборку добавиться просто ограничение на тип связи.

Так хранить друзей это не очень хорошая идея. Если на сайте будет 1000 пользователей и у каждого по 100 друзей, то у вас будет таблица на 200000 записей, и довольно медленные запросы для такой простой штуки как список друзей.
Я бы сделал денормализацию, то есть просто хранил бы список друзей строкой в поле модели user 🙂
Быстрые запросы, так как пропарсить строку в несколько сотен символов будет быстрее, чем делать запрос к таблице в несколько сотен тысяч записей, да и в разработке такой способ проще.
Хотя возможно я ошибаюсь и разница в производительности будет не такой большой.

Читайте также:  Сколько байт float python

Собственно, отвечаю на ваш вопрос. Нужно просто получить список всех записей, где user1 есть в поле user или friend, затем уже в коде определить, взаимные это друзья (есть запись где user1 в поле friend, и запись где user1 в поле user, второй пользователь одинаковый в обоих запросах) или кто-то из них только отправил запрос. Запрос будет чем-то вроде:
select user, friend from friends where user=:user_id or friend=:user_id

Не, ну хранить друзей в поле таблицы users это что-то вообще странное. А если у пользователя 10 000 друзей, а id-шник — это число порядка миллиона? Какой длины строка будет? Ужас же

> у вас будет таблица на 200000 записей
И что? И 50 лямов — не проблема для тупого индекс-скана даже на убитой виртуалке.

А вот хранить массив в поле таблицы — ветвь тупиковая. Чуть только понадобится найти «кто добавил в друзья меня», а не кого добавил этот пользователь — сразу получается full-scan, который быстро выполняться не может в принципе.

теоретически вам надо два множества — друзья юзера, и обратное — те кто позвал в друзья вашего юзера.

1. select f1.friend from friends f1 where f1.user=:user_id 2. select f1.user from friends f1 where f1.friend=:user_id 

пересечение будет давать взаимных френдов, вычитания — невзимных с одной и с другой стороны.
синтаксис SQL говорит что это легко можно сделать полным join, который обычно не имплементируется но эмулируется обьединением left и right. То бишь:

select * from friends f1 LEFT join friends f2 on f1.user=f2.friend and f2.user=f1.friend where f1.user=:user_id UNION select * from friends f1 RIGHT join friends f2 on f1.user=f2.friend and f2.user=f1.friend where f2.friend=:user_id 

и будет 3 варианта — обе f1 и f2 не null — взаимные друзья или один из них null

Но это не самый эффективный способ, я бы согласился с serso и посоветовал иметь доп колонку с типом ( заодно можно их иметь несколько — друзья, супруги/любовники, коллеги ) и при добавлении проверять обратное отношение и сразу заполнять колонку. На нагруженной системе это можно делать в отложенном режиме.

Источник

Система друзей на PHP

Сделайте отдельную таблицу для заявок, к примеру reguests. Пускай она будет примерно так:

 | id | sender | taker | accept | 

Первые три поля понятны, а вот accept пускай имеет значения 1 или 0 в зависимости подтверждения заявки. То есть 1, если подтвердил, 0 если еще нет.

Чтобы реализовать систему друзей, то сделайте таблицу frinends (к примеру) и пускай она имеет примерно такой вид:

В поля id1 и id2 вписываете двух человек, которые подружились. Потом просто проверяете наличие пары нужных ид в таблице.

Читайте также:  Python programming questions and answers

Вот. Коротко и думаю ясно) Недавно сам ломал голову над такой системой, так что буду рад помочь.

А одной таблицей обойтись нельзя? Допустим всё поместить во вторую, friends. И ещё такой вопрос, как я понял в поле id идёт пара двух id (id1 + id2)?

@ka5itoshka , в поле id — идет ид самой строки (ну вдруг пригодится параметр. id людей в этом столбце не учавтсвуют). А если помещать всё в одну таблицу, то там придется использовать explode и больше циклов — а это грузит память. Так что две таблицы вполне достаточно 😉

@Эмиль Сабитов, я просто не могу понять как в вашей реализации вывести нужную мне информацию )) т.е. пользователь, друзей которого мы хотим вывести может быть в кое каких случаях id1 или же id2 (Допустим первый случай — я отправил заявку Вам, второй я получил заявку от Вас и в обеих случаях заявки подтверждены, да?. А тут есть пользователь который вообще не принял заявку (игнорирует) и нам такого не нужно выводить (т.е. выведем только тех с кем 100% подружились)))

SELECT тут что нужно выбрать FROM reguests WHERE ( id =’нужныйчел’ OR id2 =’нужныйчел ) AND accept`=1

Предположим, что таблица с пользователями у вас уже есть. Остаётся создать таблицу, в которой буду «статусы» отношений между ними и, если нужно, то можно сделать еще одну таблицу, в которой будут храниться значения статусов

Таблица users_status:

  • user_inviter (id юзера, который пригласил)
  • user_invited (id приглашенного юзера)
  • stat_val_id (текущий статус — ключ к полю stat_id в таблице ниже)

Таблица status_value

SELECT * FROM `userlist` WHERE `user_id` IN ( SELECT IF(`user_invited` = '3', `user_inviter`, `user_invited`) FROM `users_status` WHERE `stat_val_id` = '2' ) 
  • user_invited = ‘3’ — «3» — id пользователя, у которого ищем друзей
  • stat_val_id = ‘2’ — «2» — статус, означающий «дружат»

В принципе всё понятно, вот только вот что: допустим мы хотим вывести друзей определенного человека. Что нужно в таком случаи указать в SELECT?

Если статус «друг» имеет то получаем id-шники всех друзей: SELECT user_invited FROM users_status WHERE user_inviter = ‘$user_id’ AND stat_val_id = ‘100500’

@Deonis, вы меня не правильно поняли. Есть страница человека с Как вывести на ней всех добавленных (взаимно) друзей. т.е. человек может быть user_inviter или user_invited и если это всё взаимно, записи должны выводиться. Вот это и есть суть проблемы.

@Deonis , Ваш способ, на мой взгляд — чуть хуже, чем я описал в предыдущем ответе. @ka5itoshka и так просил одной таблицей сделать, у Вас уже 3. Может еще по-другому можно сделать?

Эмиль Сабитов, по поводу таблицы со значениями — это, как я сказал, «если нужно» и абсолютно не обязательно. Вам достаточно знать их значения, например, 1 -> пригласил, 2 -> принял, 3 -> отклонил. А по поводу второго замечания, то тут нужен просто правильно составленный запрос. Смотрите вариант по этой ссылке, но я в запросах не так силён, как, допустим, @Yura Ivanov, поэтому не против, чтоб он оптимизировал его.P.S. Проапдейтил так же и свой ответ.

Читайте также:  Startactivityforresult is deprecated java

Тут можно обойтись и одной таблицей со полями userId1, userId2, status. Рассмотрим пример вконтактика — там если отправляешь заявку добавления в друзья, то становишься подписчиком, а когда заявку подтверждают, то друзьями. Здесь поле статуса отвечает как раз за определение типа связи, а их смена должна быть определена в триггерах. На уровень приложения смену статуса выносить не стоит.

Пример. Пользователь делает заявку на добавление в друзья, при этом выполняется запрос:

insert into friends_rels (userId1, userId2) values ($id1, $id2); 

А уже триггер должен определить является ли это заявкой, или же подтверждением. Определяет путем запроса к таблице:

select userId1, userId2 from friends_rels where userId1 = $id2 and userId2 = $id1; 

Если находит, значит это подтверждение заявки: модифицирует строку NEW.status = ‘friends’ и выполняет update на заявку, где также присваивает статус того, что они — друзья. Если же запись селектом не была найдена, то значит это заявка на добавление в друзья и нужно лишь модифицировать статус: NEW.status = ‘subscribe’.

Первичный ключ для строки не стоит делать — он попросту не нужен, а нужно только повешать уникальность на сочетание двух полей.

Таким образом вся логика сосредоточена в одном только триггере на уровне БД, т.е. на уровне хранения данных. Отсутствуют лишние Joinы для определения типа связи. Также не нужно обрабатывать кучу частных ситуаций типа той, когда одной пользователь сделал заявку второму, а второй пользователь сделал заявку на добавление в друзья первого — здесь все пройдет верно, а в других реализациях возможно отклонение от требуемого поведения.

Источник

php mysql + create a friend request system

if the user has already send the request i will echo a message to infor the user that a request had been send.

but the error is that i am in the first condition because the system display that the user is the owner profile but this is wrong

this is a chunk of code

request_as_friend.php

 if($mem1==$mem2) < echo "Error you can not add yourself as friend"; exit(); >require_once('../include/connect.php'); if($_POST['request']=="requestFriendship") < //check that there is not a request pending where this viewer is requesting this profile owner $sql = mysql_query("SELECT id FROM friend_requests WHERE mem1='$mem1' AND mem2='$mem2'limit1")or die(mysql_error()); $numRows = mysql_num_rows($sql); if($numRows >0) < echo "You have a friend request pending already for this member. they must approve it when they view their request list"; exit(); >//check that there is not a request pending where this profile owner is not already requesting this viewer $sql = mysql_query("SELECT id FROM friend_requests WHERE mem1='$mem2' AND mem2='$mem1'limit1")or die(mysql_error()); $numRows = mysql_num_rows($sql); if($numRows > 0) < echo "This user has requested you as friend already! Check your friend Request on your profile"; exit(); >$sql = mysql_query("INSERT INTO friend_requests(mem1,mem2,timedate) VALUES('$mem1','$mem2',now())") or die (mysql_error("friend request insertionn error")); //$sql = mysql_query("INSERT INTO pms(to,from,time,sub,msg) VALUES('$mem2','XXXXX',now(),'New Friend Request','YOU Have a New friend request waiting for approval.

Navigate to your profile and check your friend request.

Thank you.')") or die (mysql_error("friend request PM insertionn error")); echo "Friend Request sent succesfully. this member must approve the request"; exit(); > ?>

Источник

Оцените статью