Как хранить друзей в базе данных
В этом разделе помещены уроки по 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 просмотра
- Вконтакте
А что если хранить немного по другому?
Например не создавать дублирующую запись в обратную сторону, а изначально использовать еще одно поле в троичной системе счисления: ± 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.
Все что выше — мое видение направления решения. Идти в этом направлении или нет — решать вам.
- Вконтакте
Так хранить друзей это не очень хорошая идея. Если на сайте будет 1000 пользователей и у каждого по 100 друзей, то у вас будет таблица на 200000 записей, и довольно медленные запросы для такой простой штуки как список друзей.
Я бы сделал денормализацию, то есть просто хранил бы список друзей строкой в поле модели user 🙂
Быстрые запросы, так как пропарсить строку в несколько сотен символов будет быстрее, чем делать запрос к таблице в несколько сотен тысяч записей, да и в разработке такой способ проще.
Хотя возможно я ошибаюсь и разница в производительности будет не такой большой.
Собственно, отвечаю на ваш вопрос. Нужно просто получить список всех записей, где user1 есть в поле user или friend, затем уже в коде определить, взаимные это друзья (есть запись где user1 в поле friend, и запись где user1 в поле user, второй пользователь одинаковый в обоих запросах) или кто-то из них только отправил запрос. Запрос будет чем-то вроде:
select user, friend from friends where user=:user_id or friend=:user_id
- Вконтакте
> у вас будет таблица на 200000 записей
И что? И 50 лямов — не проблема для тупого индекс-скана даже на убитой виртуалке.
А вот хранить массив в поле таблицы — ветвь тупиковая. Чуть только понадобится найти «кто добавил в друзья меня», а не кого добавил этот пользователь — сразу получается full-scan, который быстро выполняться не может в принципе.
теоретически вам надо два множества — друзья юзера, и обратное — те кто позвал в друзья вашего юзера.
пересечение будет давать взаимных френдов, вычитания — невзимных с одной и с другой стороны.
синтаксис SQL говорит что это легко можно сделать полным join, который обычно не имплементируется но эмулируется обьединением left и right. То бишь:
и будет 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, поэтому я думаю, что первый метод использования отдельной таблицы вызовет огромное количество запросов к базе данных?