Общий ответ - найти расстояние между владельцем документа и данным контактом. С точки зрения компьютерных наук, это ориентированный граф .
Есть хорошая статья с некоторыми SQL-запросами, которая охватывает эту тему на http://techportal.inviqa.com/2009/09/07/graphs-in-the-database-sql-meets-social-networks/. Вместо того, чтобы пытаться обобщить всю статью, вот как концептуализировать проблему:
- Начните с чистого листа бумаги.
- Нарисуйте точку где-нибудь на странице для каждого человека (в данном случае, пользователей A, B и C). В терминах CS это «узел».
- Нарисуйте стрелку от пользователя ко всем его контактам. В терминах CS это «направленный край» или «дуга».
- Это не совсем ясно в вопросе, но похоже, что пользователь C должен быть контактом пользователя B или контактом с другими контактами пользователя A (поскольку пользователь A может читать C2 и C4).
- Таким образом, в этом случае вы будете использовать пользователя A -> пользователя B и пользователя B -> пользователя C.
Кроме того, если «контакт» является взаимным, вы можете нарисовать отрезок линии (или двунаправленную стрелку) вместо стрелки. В терминах CS это будет «неориентированный» или «направленный» граф. Отношения в Facebook - это неориентированные отношения; если кто-то мой друг, то я тоже их друг. Напротив, если кто-то есть в моей адресной книге Outlook, я не обязательно в их. Так что это целенаправленные отношения.
Чем больше пользователей будет добавлено к чертежу, вы заметите, что контакты пользователя находятся в одном шаге, а их контакты - в двух шагах. Но вы можете двигаться только в направлении стрелки.
Итак, проблема для контактов: «Как мне найти все узлы, расстояние между графами которых равно единице? И вопрос для контактов: «Как мне найти все узлы, расстояние между графами которых равно двум?». Хотя «два или меньше», вероятно, более уместно, так как можно ожидать, что прямые контакты будут иметь доступ ко всему содержимому «контактов».
Для общего случая в статье описаны некоторые SQL-запросы, которые могут дать некоторое представление. Но для вашей конкретной цели я бы хотел использовать несколько соединений.
Давайте рассмотрим таблицу Users
с первичным ключом id
вместе с другими его полями и таблицу HasContact
, которая имеет только два столбца: userId
и contactId
. Предположим, что у пользователя A есть идентификатор 1, у пользователя B - 2, а у пользователя C - 3. HasContact имеет строки (1, 2) и (2, 3) для представления взаимосвязей, описанных выше.
Довольно простой набор соединений SQL может создать список всех друзей или всех друзей друзей.
Следующий запрос вернет все идентификаторы контактов пользователя:
SELECT contact.id
FROM Users "user"
LEFT JOIN Relationships "rel"
ON user.id = rel.userid
LEFT JOIN Users "contact"
ON rel.contactId = contact.id
WHERE user.id = $id_of_current_user
Если вам известны идентификаторы пользователей, запрос авторизации может быть довольно простым:
SELECT count(*)
FROM Relationships "rel"
WHERE rel.userid = $document_owner_user_id
AND rel.contactid = $id_of_current_user
Если запрос возвращает 0, то мы знаем, что текущий пользователь , а не один из контактов владельца документа.
Мы можем обновить этот второй запрос, чтобы указать, является ли пользователь контактом:
SELECT count(*)
FROM Relationships "rel_1"
INNER JOIN Relationships "rel_2"
ON rel_1.contactId = rel_2.userId
WHERE rel_1.userid = $document_owner_user_id
AND rel_2.contactid = $id_of_current_user
Это должно возвращать ненулевое значение, если в таблице «Отношения» есть записи, такие что ($document_owner_user_id, X)
и (X, $id_of_current_user)
существуют. В противном случае он вернет ноль.
Я знаю, что это длинный и несколько косвенный ответ, поэтому, пожалуйста, прокомментируйте, если у вас есть какие-либо вопросы.