PHP: Idea for friend-system? - php

I need help on making a friend-system.
I am thinking how to make so both users can see that they are friends together.
Should i just make a user1 field and user2 field, and then when displaying him/her´s friends, it should select where user1 ='$id' OR user2 = '$id' ?
Or should i make two rows each time people are being friends?
Smart way and example would be appreciated. Thank you.
I am storing in mysql database.
My thoughts is exactly in how should i list that who is friend with who. Lets say i use method 1) with user1 and user2 column, then i should have WHERE user1 or user2 is $id (users id) but can this work properly?
I just tried this and it shows the userid for user2 in user1´s friendslist,
but in user2´s friendslist it just shows his own userid and not the user1s..

On a big projects with sharding you should always replicate data for each user.
For not so big project it's okay to keep one table with "initiator" and "accepter" fields for user_id. Don't forget to add indexes and "status" field for friendship

I'm assuming you're storing them in a database. A simple way would be to have a new table, lets call it "friendships" with two columns, user_1, user_2. If two users are friends, they should have a row in this table. This is an extremely simple way of implementing this, but it should work.

SELECT users.name, fr.name
FROM users, friends, users AS fr
WHERE users.user_id = ?
AND users.user_id = friends.user_id1
AND friends.user_id2 = fr.user_id
UNION
SELECT users.name, fr.name
FROM users, friends, users AS fr
WHERE users.user_id = ?
AND users.user_id = friends.user_id2
AND friends.user_id1 = fr.user_id
This will allow you check against an intermediary table for your many-to-many relationship and not have to duplicate (inverse) rows.
CREATE TABLE `users` (
`user_id` bigint(20) unsigned NOT NULL AUTO_INCREMENT,
`name` varchar(50) NOT NULL,
PRIMARY KEY (`user_id`),
);
CREATE TABLE `friends` (
`user_id1` bigint(20) unsigned NOT NULL,
`user_id2` bigint(20) unsigned NOT NULL,
PRIMARY KEY (`user_id1`,`user_id2`)
);

Some good answers here, If I had to do this I would do it one way, this way you can determine if the friendship has been confirmed and also ensure the friendship is mutual, so for example
Lets assume status has two values
0 = Unconfirmed
10 = Confirmed
Using simple tables with status for acceptance levels
CREATE TABLE `users` (
`id` bigint(20) unsigned NOT NULL AUTO_INCREMENT,
`name` varchar(50) NOT NULL,
PRIMARY KEY (`user_id`),
);
CREATE TABLE `friend` (
`user_id` bigint(20) unsigned NOT NULL,
`friend_id` bigint(20) unsigned NOT NULL,
`status` int(11) unsigned NOT NULL,
PRIMARY KEY (`user_id`,`friend_id`)
);
INSERT INTO `users` (`id`, `name`) VALUES
(1, 'Jack'),
(2, 'John');
Jack would like to be friends with John, so you would create a relationship between the two only one way:
INSERT INTO `friend` (`user_id`, `friend_id`, `status`) VALUES (1, 2, 0);
Now you can query the database to find Jacks friends or Jacks requests and Johns friends or Johns requests using simple queries
To find Jacks unconfirmed friends you would use something like
SELECT users.* FROM users JOIN friend ON users.id = friend.user_id WHERE friend.friend_id = 1 AND friend.status = 0
To find Jacks confirmed friends you would use something like
SELECT users.* FROM users JOIN friend ON users.id = friend.user_id WHERE friend.friend_id = 1 AND friend.status = 10
To find Jacks any friend requests you would use something like
SELECT users.* FROM users JOIN friend ON users.id = friend.user_id WHERE friend.friend_id = 1
When someone makes a confirmation of friendship you would perform 2 queries, one for updating the record and one as a reverse confirmation
UPDATE friend SET status = 10 WHERE user_id = 1 AND friend_id = 2;
INSERT INTO `friend` (`user_id`, `friend_id`, `status`) VALUES (2, 1, 10);
On a different note, I would also use a Graph database for complex relationship queries whilst maintaining a firm copy in the MySQL database
Graph teaser for friends of friends to build relationships
MATCH (Person { id: 1 })-[:knows*2..2]->(friend_of_friend) WHERE NOT (Person)-[:knows]->(friend_of_friend) AND NOT friend_of_friend.id = 1 RETURN friend_of_friend.id, friend_of_friend.name LIMIT 10

Related

exclude records that exist in another table

I got 2 tables like these:
emails:
emailID int(10) auto_increment, memberID int(10), emailData text, and so on
members:
memberID int(10) auto_increment, user_name char(40), password char(50), and so on
My query is this:
select
emails.emailID, emails.emailData,
members.memberID, members.user_name
from emails, members where
emails.memberID = members.memberID
Now I've added two more tables like these:
blocked:
id int(10) auto_increment, memberID int(10), blocked_memberID int(10)
markedAsRead:
id int(10) auto_increment, memberID int(10), emailID int(10)
I want to modify my original query so that it excludes memberID which are in blocked.blocked_memberID and also excludes emailID which are in markedAsRead.emailID
How can I do this?
You can use NOT EXISTS :
SELECT ....
FROM ....
WHERE ..... // Replace the dots with Your Query
AND NOT EXISTS(SELECT 1 FROM blocked
WHERE emails.memberID = blocked.memberID)
AND NOT EXISTS(SELECT 1 FROM markedAsRead
WHERE emails.emailID = markedAsRead.emailID)
You could also lookup for LEFT JOINS or NOT IN to exclude records that doesn't exists in a particular table.
EDIT: Usually EXISTS() and LEFTJOIN have similar performaces, sometime it can even perform better than a join.
LEFT JOIN sulotion:
SELECT ...
FROM ...
LEFT JOIN blocked
ON(WHERE emails.memberID = blocked.memberID)
LEFT JOIN markedAsRead
ON(emails.emailID = markedAsRead.emailID)
WHERE ...
AND blocked.memberID IS NULL
AND markedAsRead.emailID IS NULL

Set random values from an array into database

I'm working on a PHP project with MYSQL database. I have a table of groups of students. Each group has an examiner. What i want to do is that i want to set two examiners for each group randomly. How to do it?
MySQL Code:
create table groups (
groupID int(10) not null,
nbStudents int not null,
avgGPA DOUBLE NOT NULL,
projectName varchar(50) not null,
advisorID int,
examiner1ID int,
examiner2ID int,
adminID int not null,
primary key (groupID)
);
create table faculty (
name varchar(30) not null,
facultyID int(10) not null,
email varchar(30) not null,
mobile int(15) not null,
primary key (facultyID)
);
examiner1ID and examiner2ID are foreign keys from the table faculty.
Here is a very convoluted way to do it. It uses 2 subqueries to pick faculty members, and insert .. on duplicate key to update the examiners IDs.
insert into groups
(groupID, examiner1ID, examiner2ID)
select groupID,
#x:=(select facultyID from faculty order by rand() limit 1),
(select facultyID from faculty where facultyID <> #x order by rand() limit 1)
from groups
on duplicate key update examiner1ID=values(examiner1ID), examiner2ID=values(examiner2ID);
#x is a user-defined-variable. In this case, it is used to store the first random faculty member. <> #x makes sure we don't pick the same faculty member in both slots.
Since groupID is a unique key, when we try to insert a row with an existing unique key, it will update the existing row instead of inserting it. That's what on duplicate key update clause is used for.
set different examiners for each group:
insert into groups
(groupID, examier1ID, examier2ID)
select a.groupID, max(if(b.id%2, b.facultyID, 0)), max(if(b.id%2, 0, b.facultyID))
from (
select #row:=#row+1 id, groupID
from groups a
join (select #row:=0) b) a
join (
select #row:=#row+1 id, facultyID
from (
select facultyID
from faculty a
order by rand()) a
join (select #row:=0) b) b on a.id = ceil(b.id/2)
group by a.groupID
on duplicate key update examiner1ID=values(examiner1ID), examiner2ID=values(examiner2ID);

How to handle a bidirectional many-to-many relationship with PHP

I am trying to setup a bidirectional many-to-many relationship using the same table data, namely User, I also have a link table named Userusers which joins the one user with another user, but I am not sure how to handle the bidirectional side, because the result of my code only shows one direction.
--Table User:
create table User (
UserID int auto_increment not null,
UserFirstName varchar(30) not null,
UserSurname varchar(30) not null,
UserTel char(10),
UserCell char(10),
UserEmail varchar(50) not null,
UserPassword varchar(50) not null,
UserImage varchar(50),
UserAddress1 varchar(50),
UserAddress2 varchar(50),
UserTown/City varchar(50),
UserProvince varchar(50),
UserCountry varchar(50),
UserPostalCode varchar(50),
Primary key(UserID)
)
--Table Userusers:
create table UserUsers (
UserID int not null,
FriendID int not null,
primary key(UserID, FriendID),
foreign key(UserID) references User(UserID),
foreign key(FriendID) references User(UserID)
)
PHP code:
$sql="SELECT * FROM User u INNER JOIN UserUsers uu ON uu.UserID = u.UserID INNER JOIN User f ON f.UserID = uu.FriendID WHERE uu.UserID = " . $_SESSION['userID'];
Actually, no, your tables do show bidirectional relationships.
Consider your table UsersUsers
The column userID represents the person who is FRIENDS WITH friendID.
Say user 1 wants to be friends with user 2
Our UsersUsers table will look like:
UserID | FriendID
1 2
Sure, we see that there is now a relationship between User 1 and 2, but we also see that User1 has initiated the friendship, showing the direction from 1 -> 2
Now when User2 wants to accept the friendship, we can insert another record into the table, making it:
UserID | FriendID
1 2
2 1
There's definitely some better meta data you can add to the relationship table to understand more about the relationship created, but the UserID field should be considered the owner, or sender, and the FriendID should be considered the receiver.
So - you already have most of the work cut out for you, now all you have to do is create your queries to act upon this bidirectional relationship.
Getting all confirmed friends for User1:
We will assume $the_logged_in_user_id = 1
SELECT * from Users U JOIN UsersUsers F ON U.UserID = F.UserID WHERE F.FriendID = '$the_logged_in_user_id'
That will show all the confirmed friendships for $the_logged_in_user_id, assuming this is what you're going for.

PHP/MySQL Search code and logic for relational database schema

I have created this database schema and with help from several users on here, I have a database which takes user submitted business entries stored in the business table, which are additionally grouped under one or several of about 10 catagories from the catagories table, in the tbl_works_catagories table by matching the bus_id to the catagory id.
For example, bus_id 21 could be associated with catagory_id 1, 2, 5, 7, 8.
CREATE TABLE `business` (
`bus_id` INT NOT NULL AUTO_INCREMENT,
`bus_name` VARCHAR(50) NOT NULL,
`bus_dscpn` TEXT NOT NULL,
`bus_url` VARCHAR(255) NOT NULL,
PRIMARY KEY (`bus_id`)
)
CREATE TABLE `categories` (
`category_id` INT NOT NULL AUTO_INCREMENT,
`category_name` VARCHAR(20) NOT NULL,
PRIMARY KEY (`category_id`)
)
CREATE TABLE `tbl_works_categories` (
`bus_id` INT NOT NULL,
`category_id` INT NOT NULL
)
Now, what i want to do next is a search function which will return businesses based on the catagory. For example, say one of the businesses entered into the business table is a bakers and when it was entered, it was catagorised under Food (catagory_id 1) and take-away (catagory_id 2).
So a visitor searches for businesses listed under the Food catagory, and is returned our friendly neighbourhood baker.
As with all PHP/MySQL, i just can't (initially anyway) get my head around the logic, never mind the code!
You should setup foreign keys in your tables to link them together.
CREATE TABLE `business` (
`bus_id` INT NOT NULL AUTO_INCREMENT,
`bus_name` VARCHAR(50) NOT NULL,
`bus_dscpn` TEXT NOT NULL,
`bus_url` VARCHAR(255) NOT NULL,
PRIMARY KEY (`bus_id`)
)
CREATE TABLE `categories` (
`category_id` INT NOT NULL AUTO_INCREMENT,
`category_name` VARCHAR(20) NOT NULL,
PRIMARY KEY (`category_id`)
)
CREATE TABLE `tbl_works_categories` (
`bus_id` INT NOT NULL,
`category_id` INT NOT NULL,
FOREIGN KEY (`bus_id`) REFERENCES business(`bus_id`),
FOREIGN KEY (`category_id`) REFERENCES categories(`category_id`)
)
Then your search query would be something like:
SELECT b.*
FROM business b, categories c, tbl_works_categories t
WHERE
b.bus_id = t.bus_id AND
c.category_id = t.category_id AND
c.category_id = *SOME SEARCH VALUE*
which using JOIN would be written as:
SELECT b.*
FROM business b
JOIN tbl_works_categories t
ON b.bus_id = t.bus_id
JOIN categories c
ON c.category_id = t.category_id
WHERE c.category_id = *SOME SEARCH VALUE*
Maybe you want something like this:
SELECT `bus_id` FROM `tbl_works_categories` WHERE `category_id` = *some id from the search*
AND `category_id` = *some other id from the search*;
Although you'd need those ids- there are a few ways to do this, I'll describe probably the most straight forward...
You get categories from $_POST, so let's just say you have 2 of them entered. (Food, and take-away). Parse these however you want, there are multiple ways, but the point is they're coming from $_POST.
execute this sort of thing for each one you find:
SELECT `category_id` FROM `categories` WHERE `category_name` LIKE '%*the name from $_POST*%';
Store these results in an array...based on how many you have there you can build an applicable query similar to the one I describe first. (Keep in mind you don't need and AND there, that's something you have to detect if you return > 1 category_id from the second query here)
I'm not going over things like security..always be careful when executing queries that contain user submitted data.
An alternate solution might involve a join, not too sure what that'd look like off the top of my head.
Good luck.
If you want all businesses that are related to the given category-id, your SQL-statement would look something like this:
SELECT `business`.`bus_name`
FROM `business`
WHERE `business`.`bus_id` = `tbl_works_categories`.`bus_id`
AND `categories`.`category_id` = `tbl_works_categories`.`category_id`
AND `categories`.`category_id` = 1;
Where 1 in this case is your food-category, but could be your PHP variable where the ID of the category the user selected is stored.
And one hint: Be sure to name your tables either in plurar or in singular. You are mixing both and could get confused.

subscription algorithm that scales

Web application PHP,Mysql. Users can write articles. How to build algorithm that allows users to subscribe (follow) to other users articles and then see list of last articles added by subscribed users? Algorithm must scale, so that one user can subscribe to 10 000 users and 10 000 users can subscribe to one user and all parts works quick - when new article added and when users looks for last articles from subscribed users.
create table `user`(
`id` INT(10) PRIMARY KEY NOT NULL AUTO_INCREMENT
);
create table `subscribes_to` (
`subscriber_user_id` INT(10) NOT NULL,
`subscribed_to_user_id` INT(10) NOT NULL, # Receiver of the subscription
PRIMARY KEY(`subscribe_user_id`, `subribed_to_user_id`),
KEY `subscriber(`subscribe_user_id`),
KEY `subscribed(`subscribed_to_user_id`);
);
# Users subscribed to role 100
SELECT distinct u.* FROM user u
JOIN subscribes_to st ON st.subscriber_user_id = u.id
WHERE
st.subscribded_to_user_id = 100;
# User 100's subsriptions
SELECT distinct u.* FROM user u
JOIN subscribes_to st ON st.subscribded_to_user_id = u.id
WHERE
st.subscriber_user_id = 100;
Additional Schema to show relationship with articles:
article (
id int(10) UNSIGNED NOT NULL PRIMARY KEY AUTO_INCREMENT,
title VARCHAR(255),
body TEXT,
date_created DATETIME,
date_updated DATETIME,
author_user_id int(10)
);
# Create new article
INSERT INTO `article` VALUES (NULL, "Hello", "This is the body", NOW(), NOW(), 1);
# Find the last 10 articles posted that user 15 suscribes to
# the author of
SELECT a.* FROM article a
JOIN user ON u.id = a.author_user_id
JOIN subscribes_to st ON st.subscribed_to_user_id = u.id
WHERE st.subscriber_user_id = 15 ORDER BY a.date_created DESC LIMIT 10;

Categories