Data Model for Social Network? - mysql

If I wanted to create a site that allowed users to have 0 or more "friends", how would I model such a relationship in a database? Would something this simple work:
Table Friends
- Id (PK)
- UserId (FK)
- FriendId (FK)
???
Would this allow me to later on do things like Facebook does (e.g. "3 of your friends knows this user, maybe you do too")? Or something like 6-degrees-to-Kevin-Bacon?
EDIT 1:
Table Friends
- UserId (FK)
- FriendId (FK)
- Status ('Pending', 'Approved', 'Rejected', 'Blocked'?)

This will work. Following are points to be noted:
Do you have something like friend confirmation. If yes, you will have to think on how to store 'pending'
Indexing both UserId and FriendId. These are the values on which you will be joining the tables.
The unordered pair (UserId, FriendId) is contender for Primary key.
Suppose Uid_1 and Fid_1 are friends where Uid_1 != Fid_1 then does your Friends Table store (Fid_1, Uid_1) as well as (Uid_1, Fid_1).
How far in degrees of relationship are you going to search.
Everytime you have to query for DOR(Degree of relationship) you will have to initialize a graph and run Shortest Path Algo (This is the least optimization I can think of). If your member-count rises to some kilos then how are you going to handle this?

You need many to many relationship - you can have 0 or more friends, every friend can have 0 or more friends. The most common approach is to bind both users in the additional table. You need just an additional DB table:
create table Relationships(
user1 int not null references Users(id),
user2 int not null references Users(id)
);
You definitely want to create indexes for user1 and user2.
I think you don't need the ID column. One more thing you should be aware of the thing that if I'm your friend, you are my friend to. When you insert ([u1],[u2]) into Relationships table check first if there is relationship ([u1],[u2]) or ([u1],[u2]). If there is such relationship don't insert another one, this could break your logic.
If you need some sort of confirmation like in most popular social networks you should make another table PendingRelationsihps which will have the same DB scheme as the Relationship one. After confirmation you will move the entry from pendingrelationships to relationsships.
Hope this will help you.

#devfreak is absolutely right, but I would not make a "Pending" table. It's simply redundant. The friend table can have a status field, and you can query against it based on status.

Related

Get a list in MySQL

I'm creating a website and users can add friends. I want them to be able to see their personal friends on a page.
For exemple:
John add user Tim and Bill.
When John goes on his friends list page, I want him to be able to see that he has Tim and Bill. How do I do that? Is that even possible? Do I need more than one table? If so, does every user has to have his own friendsList table?
Yes this is possible, you do this by querying the information from the database, the answer for if you need multiple tables etc all depends on your current table structure but at the very least you need to have some way of referencing that a Person 'John' has friends, wether thats just a 'friendID' in the same 'Person' table, or another means of doing so. then it is just a matter of querying the data correctly to return what you want and bind to the websites fields :D
One way of defining the structure is the following:
Person
PersonId
Name
<other person fields>
Relationship
RelationshipId
Name --> allow to define multiple relation types like Friendship, Follows etc.
Relationship
RelationshipId
Person1Id --> FK to Person
Person2Id --> FK to Person
RelationshipTypeId --> FK Relationship
Basically, you use an n:n between Persons (anyone can have any number of friends) and also allow for other types of relationships.
Assuming you already have a table of users, one approach would be to create a "friends" table which relates users to other users.
CREATE TABLE friends (
`user_id` INT NOT NULL,
`friend_id` INT NOT NULL
);
Both user_id and friend_id would have foreign key constraints on your existing users table (so that you guarantee an id must exist in your user table in order for it to exist in the friends table as either a user_id or friend_id).
You can then link your user table on users.id = friends.friend_id to get the friend's info.
Here is a SQL Fiddle Demo showing how this works.
You should consider using an ON DELETE CASCADE constraint on the friends table, so that if a user is deleted from the user table, the associated records in the friends table are also deleted.

Database structure suggestion (serialization or separate table)

I am currently making a database, and truth to be told I'm not exactly very good at it (kinda being forced to do it). Its a game database, and I have a table called game_table that I use for storing game sessions that users create.
The question is, what is the best way to store a list of invited users, requested users, confirmed users, declined users and pending users? Currently I am serializing the user IDs (e.g. invited users = "11235|2510|34630|45715|64530"). However, the main problem is that the field becomes not searchable, and it becomes a problem if I want to retrieve a list of games that a user is invited to. To solve that problem, I store a separate field in the user_table for invited_games (also serialized game IDs).
The problem with that, is that it is getting hard to maintain whenever I want to add new features, and it is too easy to make mistakes with keeping the serialized data in sync. Is it better to have separate tables like:
invited_users_table
Game_ID | User_ID
51 | 5193
51 | 10458
51 | 235
901 | 1536
901 | 4573
Or is there some other better way of storing these types of data? Please help, and thanks!
From what you say, it sounds like you need one table with three columns:
GameId
UserId
UserType
The latter would take on values such as "invited", "confirmed", "requested" and so on.
You would want separate tables if you had more information about the different groups. For instance, you might have a "who invited" column for invited users, or a "confirmation time" for confirmed users. If the number of specific columns needed for the different groups is large-ish, then you might want to think about a more complex data structure. If there are just a handful of such columns, you can add them into the table described above.
Yes, it is better to have a separate table for invited users.
Yet better would be to have game_user_relation table, which will store the game id, the user id and the relationship between them. Kinda:
create table game_user_relation(
game_id int not null,
user_id int not null,
relation_type varchar (10) not null,
primary key(game_id, user_id, relation_type)
) engine=InnoDB;
This table will allow one user to have many relations to one game.
Or, if you need to have exactly one user relate to one game - remove relation_type from primary key.
This way you could select all needed data from one table.

Comments on many tables database design issue

I have tables:
Articles{...}
Recipes{...}
Notifications{...}
Photos{...}
And I need to implement 'user comments' feature (like facebook).
Should I make tables: ArticleComments, RecipesComments etc. with 1:n relationship?
Or create one Comments table for all (but I have no idea how to design this)?
You could create another table CommentableEntity (although call it something better). Each of the rows in your tables (Articles, Recipes etc.) would have a reference to a unique row in this table. The entity table might have a type field to indicate the type of entity (to aid reverse joining).
You can then have a Comment table that references CommentableEntity, in a generic fashion.
So for example you'll end up with the following tables:
Articles
-----------------
Article_id
CommentableEntity_id (fk, unique)
Content
....
Recipes
-----------------
Recipe_id
CommentableEntity_id (fk, unique)
Content
....
CommentableEntity
-----------------
CommentableEntity_id (pk)
EntityType (e.g. 'Recipe', 'Article')
Comment
-------
Comment_id (pk)
CommentableEntity_id (fk)
User_id (fk)
DateAdded
Comment
...etc...
You can add the CommentableEntity record every time you add an Article/Recipe etc. All your comment-handling code has to know is the CommentableEntity_id - it doesn't care what type of thing it is.
That depends on how your application will be using comments.
My guess is that you'll frequently want to pull up all the comments a user has created regardless of the entity that they are commenting on. That is, I assume you'll frequently want a query that returns rows indicating that user JohnDoe commented on Article 1, then Photo 12, then Recipe 171. If that's the case, then it would make far more sense to have a single Comments table with a structure similar to what Steve Mayne has suggested with the CommentableEntity table.
On the other hand, if you would only be accessing the comments for a particular item (i.e. all comments for Article 1), separate ArticleComments and PhotoComments tables may be more appropriate. That makes it easier to have foreign keys between the entity table and the comment table and is potentially a bit more efficient since it's a poor man's partitioning. Of course, as soon as you start having to combine data from multiple comment tables, this efficiency goes away so you'd need to be reasonably confident about the use cases.
The easiest way would to have a 'polymorphic' comments table that would have columns for both the id and the type of the object that it refers to.
The you could do the following:
SELECT * FROM Comments where type = "Articles" and type_id = 1;
SELECT * FROM Comments where type IN ("Recipes", "Photos")
Putting a unique compound index on (type, id) would also improve the performance of the look ups.
SELECT TOP 1000 [Comments_Id]
,[Comments_Text]
,[Comments_IsApproved]
,[Comments_IsVisible]
,[Comments_DateStamp]
,[Type_Id]
,[Entity_Id] -- From Entity Table, listing Articles, Recipes etc.
,[EntityItem_Id] -- One of the PK from table of Articles, Recipes etc.
,[User_Id]
FROM [tbl_Comments]
To have an idea on how to create a single Comments table for all objects, you can take a look at django comment model ( http://docs.djangoproject.com/en/dev/ref/contrib/comments/models/ )

Database structure: Would this structure work with this m:m?

Here is my issue: (Using MySQL)
I have 2 entities called 'shops' and 'clients'. I also have a M:M table between 'clients' and 'shops' called 'clients_shops' (CakePHP naming convention). The reason I am doing it this way is that this is a SaaS application where 'clients' may have many 'shops' and 'shops' will definitely have many 'clients'.
However, I don't want to give a shop the ability to UPDATE/DELETE a 'client' record since what really needs to happen is that the 'shop' will EDIT/DELETE that 'client' from their own records, rather than from a master 'clients' table which is managed by the 'clients'.
Anyway, using this structure a 'shop' can run a query on the 'clients_shops' table to get a list of their clients and a 'client' can run a query a get a list of their 'shops'. Good so far...
So far, the database looks like this:
table.clients
client_id (PK, AI, NN)
table.shops
shop_id (PK, AI, NN)
table.clients_shops
clients_shops_id (PK,AI,NN)
client_id (FK)
shop_id (FK)
The ORM looks like this:
shops hasMany clients_shops
clients hasMany clients_shops
So far so good (I think...) but here is my question. Let's say that there is a third table named 'trips'. The 'trips' table stores information on individual bookings whereby a 'client' will make reservations for a 'trip' that is provided by a 'shop'. This is where my brain is getting mushy. How should I set this relationship up?
Is it this way:
table.trips
trips_id (PK,AI,NN)
clients_shops_id (FK) [which would contain keys for both the shop and the client]
Or is there a better way to do this, like another table that uses clients.client_id AND clients_shops.clients_shops_id.
Thanks in advance to anyone that actually read this whole thing!
Unless it's required by your ORM, you don't need a surrogate foreign key for clients/shops and everything that refers to it.
Make a composite PRIMARY KEY instead and refer to it from elsewhere:
CREATE TABLE clients_shops
(
client_id INT NOT NULL,
shop_id INT NOT NULL,
PRIMARY KEY (client_id, shop_id)
);
CREATE TABLE trips
(
trip_id INT NOT NULL PRIMARY KEY,
client_id INT NOT NULL,
shop_id INT NOT NULL,
trip_data …,
CONSTRAINT fk_trips_clients_shops
FOREIGN KEY (client_id, shop_id)
REFERENCES clients_shops
);
This model assumes that you maintain clients/shops relationships separately from the clients' transactions and not let clients buy from the shops unless they are "related".
Probably you want the relationship to appear automatically whenever a trip is ordered by a client from a shop. In this case, you only need the second table, and the first table is a mere
SELECT DISTINCT client_id, shop_id
FROM trips
Here is the Logical Diagram to handle what you are looking for. Depending on your requirements you can change the non-identying relationships (Client::Trip & Shop::Trip) to identifying relationships. If you do though I would limit it to only changing the Shop::Trip to identifying though. Also make changes to the Cardinality as you see fit.
I would probably make the trips table like this:
table.trips
trip_id (PK)
shop_id (FK to shops)
client_id (FK to clients)
other_trip_column_etc
I would not reference the m-m table clients_shops from the trips table - just reference the shop and client tables with individual foreign keys.
The clients_shops table represents the current relationship between a client and a shop. The trip should not depend on these relationships, because they could potentially change in the future, and you probably wouldn't want the trip's data to change over time - it should be a transactional record that specifies exactly what shop, client, and trip was scheduled at that given time, regardless of the current relationship between that client and shop.

mysql: proper way to handle relation between users and teams?

Newish to mysql DBs here. I have a table of USERS and a table of TEAMS. A user can be on more then one team. What's the best way to store the relationship between a user and what teams he's on?
Lets say there are hundreds of teams, each team consists of about 20 users, and on average a user could be on about 10 teams, also note that users can change teams from time to time.
I can think of possibly adding a column to my TEAMS table which holds a list of user ids, but then i'd have to add a column to my USERS table which holds a list of team ids. Although this might be a solution it seems messy for updating membership. It seems like there might be a smarter way to handle this information... Like another table perhaps? Thoughts?
Thanks!
ps, whats the best field type for storing a list, and whats the best way to delimit?
whats the best field type for storing a list, and whats the best way to delimit?
It's usually a really bad idea to try to store multiple values in a single column. It's hell to process and you'll never get proper referential integrity.
What you're really looking for is a join table. For example:
CREATE TABLE user_teams (
user_id INT NOT NULL FOREIGN KEY REFERENCES users(id),
team_id INT NOT NULL FOREIGN KEY REFERENCES teams(id),
PRIMARY KEY (user_id, team_id)
);
so there can be any number of team_ids for one user and any number of user_ids for one team. (But the primary key ensures there aren't duplicate mappings of the same user-and-team.)
Then to select team details for a user you could say something like:
SELECT teams.*
FROM user_teams
JOIN teams ON teams.id= user_teams.team_id
WHERE user_teams.user_id= (...some id...);