Как хранить друзей в базе данных

от admin

Как хранить друзей в базе данных

В этом разделе помещены уроки по PHP скриптам, которые Вы сможете использовать на своих ресурсах.

Фильтрация данных с помощью zend-filter

Когда речь идёт о безопасности веб-сайта, то фраза "фильтруйте всё, экранируйте всё" всегда будет актуальна. Сегодня поговорим о фильтрации данных.

Контекстное экранирование с помощью zend-escaper

Обеспечение безопасности веб-сайта — это не только защита от SQL инъекций, но и протекция от межсайтового скриптинга (XSS), межсайтовой подделки запросов (CSRF) и от других видов атак. В частности, вам нужно очень осторожно подходить к формированию HTML, CSS и JavaScript кода.

Подключение Zend модулей к Expressive

Expressive 2 поддерживает возможность подключения других ZF компонент по специальной схеме. Не всем нравится данное решение. В этой статье мы расскажем как улучшили процесс подключение нескольких модулей.

Совет: отправка информации в Google Analytics через API

Предположим, что вам необходимо отправить какую-то информацию в Google Analytics из серверного скрипта. Как это сделать. Ответ в этой заметке.

Подборка PHP песочниц

Подборка из нескольких видов PHP песочниц. На некоторых вы в режиме online сможете потестить свой код, но есть так же решения, которые можно внедрить на свой сайт.

Совет: активация отображения всех ошибок в PHP

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

Агент

PHP парсер юзер агента с поддержкой Laravel, работающий на базе библиотеки Mobile Detect.

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

Как хранить связи вида пользователь-друг — понятно. Создаем таблицу 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 (принять заявку)

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

  • Вопрос задан более трёх лет назад
  • 10784 просмотра
  • Facebook
  • Вконтакте
  • Twitter

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

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

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

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

  • Facebook
  • Вконтакте
  • Twitter

Просто тогда непонятно как выбирать друзей пользователя. Если делать что-то вроде 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.

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

  • Facebook
  • Вконтакте
  • Twitter

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

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

  • Facebook
  • Вконтакте
  • Twitter

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

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

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

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

Читать:
Как уменьшить пинг на 4g модеме

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

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

Как лучше всего хранить данные о "друзьях" пользователя в базе данных?

Столкнулся с проблемой. Как лучше всего записывать «друзей» пользователя. Сначала я думал, что буду записывать так.

Но когда понял, что когда на сайте будет хотя бы 5000 пользователей — база будет огромной.
Подскажите, как лучше всего хранить это в базе?

30 млрд -у фейсбук стока не будет.

Такая таблица имеет смысл существования, но у неё есть свои недостатки.

1 из которых. Вот именно в данном примере мы видим что у пользователя 1 есть 3 друга.

допустим запрос будет выглядеть так

Получим список друзей пользователя 1. Вроде все бы ничего получили список. Но встает вопрос вот все друзья пользователя 1 приняли его в друзья.

тогда запрос вида

Должен возвратить список друзей пользователя 2, он это сделает, но сделает в том случае если только пользователь 2 первый предложил дружбу, тогда будет запись

т.е. пользователю 2 не вылезет инфа что он дружит с пользователем 1.

Это самый существенный косяк.

Но его можно избежать так. Допустим пользователь 1 подал заявку на пользователя 2. создалась запись

Когда пользователь 2 подтвердил заявку в друзья — создается симметричная запись.

Но это увеличение БД ровно в 2 раза, что не есть хорошо.

Решение и тут есть, на мой взгляд.

Добавить 3е поле.

link — в данном случае имеет значение 0 — т.е. пользователь 2 принял заявку в друзья. 1 — не принял. И сразу видно кто предложил дружбу, в данном случае пользователь 2.

Это уменьшит кол-во записей в таблице. Но запрос на выборку друзей тогда будет немного другой.

Но тут опять же тупик в плане вытаскиваются 2 поля, и нужно проверять их значения, что для последующей оптимизации вообще не айс.

Есть вариант на мой взгляд простой, но @Mr Trololo Вы ему за ответ поставили минусы. Но он в чем-то прав товарищи.

Рассмотрим пример. Есть у нас таблица

В чем фишка, мы храним в поле не просто строку 2,4,55,123 а массив ID пользователей, у каждого он свой, на каждого пользователя 1 запись в БД, расти такая таблица будет несомненно но уже меньше чем предыдущий вариант. В чем прикол массива

  • Получить список пользователей просто
  • Получить список общих друзей тоже. Как? array_intersect возвращает общие значения из нескольких массивов.
  • Добавить/удалить/изменить значение в массиве достаточно просто.
  • В такой записи можно указывать и отношение связей, добавлять при этом доп поле не нужно, все в массиве. Как? Допустим есть значение 23. Оно положительное, значит примем за правило, если в массиве ID пользователя записан положительно, значит он предложил дружбу, если отрицательное, то ему предложили. array(«-23″,»2″,»-5″,»6″); двоих пригласил он двое пригласили его.
  • Как-то нужно учитывать принятие в друзья!? Да, не вопрос сделайте в этом же массиве перед ID пользователя array(«?23″,»2″,»?5″,»?6″); знак ? это значит что решение о дружбе еще не принято. Ну или другой знак, символ.+ есть 2 варианта вы добавляете и вас добавляют, если вы добавляете тогда ставьте ? один знак, если вас добавляют ?? два знака
  • Да при таком раскладе есть дублирование информации, но вытащить её в последствии проще.
  • Хранить её можно в сериализованном массиве, в JSON кому как удобнее. Но в данном случае именно массив это чтобы работала array_intersect она есть в php.
  • Найти кто добавил в друзья меня

select user-id-two from friends where user-id-one=UID // получим список всех пользователей Далее из массива вычленить отрицательные значения. Да скажите что это геморрой, но в данном случае вы же можете этот запрос закешировать! И данные у вас всегда под рукой!

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

Примерное описание такой. Давайте кидайте помидоры! Только свежие, я их люблю 🙂

В общем сначала скушайте эту информацию, думаю это один из правильных вариантов решения вопроса о дружбах на сайтах. Это один из вариантов решения, он не претендует на правильность, т.к. только что написал всю эту многабукф сюда. Это просто представление решения проблемы

Хранение друзей в базе данных для социальной сети

Для хранения отношений друзей в социальных сетях лучше иметь другую таблицу с столбцами relationship_id, user1_id, user2_id, time_created, pending или если подтвержденный пользователь user_id будет серализован/взорван в одну длинную строку и сохранен вместе с другими данными пользователя, такими как user_id, name, dateofbirth, address и ограничивать, как только 5000 друзей, похожих на facebook?

Есть ли лучшие методы? Первый метод создаст огромную таблицу! Второй имеет один столбец с очень длинной строкой.

На странице профиля каждого пользователя все его друзья должны быть извлечены из базы данных, чтобы показать как 30 друзей, похожих на facebook, поэтому я думаю, что первый метод использования отдельной таблицы вызовет огромное количество запросов к базе данных?

Похожие статьи