I’m working on a community portal. The portal has members (tbl members) and members can has friends (tbl member_friends), as on most social networks. In order to avoid double entries in the member_friends table I altered this table the following way:
ALTER TABLE `member_friends` ADD UNIQUE KEY `friend_combination` (`member_one_id`, `member_two_id`);
I thought by doing so I would avoid double entries for similar id combinations
But when I add a friendship combination:
INSERT INTO `member_friends` (`member_one_id`, `member_two_id`) VALUES
(1, 2);
and after that doing the same but the other way arround:
INSERT INTO `member_friends` (`member_one_id`, `member_two_id`) VALUES
(2, 1);
The row is still added. What should I change or update to avoid double entries for two id’s no matter in which order.
I’m not convinced there is an issue here. The fact that I consider someone to be my friend does not mean they consider me to be their friend as well.
If that is the case in your application though then:
You should not call it a friendship, because it and doesn’t behave like one, and
Whenever a user A friends a user B, add both tuples (A, B) and (B, A) in the database. That way it can not be inserted again and it makes your queries a) a lot easier to understand and b) more efficient
@r937 In this case It’s not really about friendship, but more about having similar interests. And indeed I don’t want to store both (1,2) and (2,1). So what are my options in this Rudi?
Edit. I know I can avoid multiple id couples with scripting but I’m just wondering if this could be done in the database allready
It happened in your test, but would it ever happen out in the wild?
If I understand how your friendship system will work, I presume something like:-
Then in the instance that the request is accepted and the pair are added to the table; would you then not have some system whereby the friends would no longer see the option to add each other as a friend, as that relationship has already been established and therefore it is unlikely the inverse pair would ever be added?
And if by some chance/bug it did, what’s the worst that could happen?
Edit: Another thought for a simple solution.
When adding the pair, have a function to always sort the pair into lowest number first before insertion, that way duplicate pairs will always be “carbon copy” duplicates that the database can refuse.
@SamA74. I have seen that suggestion somewhere else as as well and have been thinking on how I could accomplisch that, but havent come up with a sollution as yet. Do you have any suggestions?
Any reason you are using a tool that was not made for this instead of one that is specifically made for it? I guarantee you facebook and twitter are not using Mysql or any other RDMS to model their relationships. You can hammer a nail with the heel of your shoe but why not just use a hammer which was designed specifically to hammer nails. Things will start getting complicated when you start asking questions like who are my friends friends or who are my friends friends that are not my friends and so on.
This. Exactly this is why I recommend to store both.
Let’s work out an example here shall we?
First let’s assume we’re only storing one direction of the “friendship”.
Let’s start with a simple query and find all friends of a certain user A.
You’d think the query is
SELECT
m.name
FROM
members AS m
INNER JOIN
member_friends AS f
ON m.id = f.member_one_id
AND f.member_two_id = ?
Right? Wrong!
The current member can either be in member_one_id or in member_two_id and you can’t know upfront, so you have to query both ways. So your query has to account for both and it would actually become:
SELECT
m.name
FROM
members AS m
INNER JOIN
member_friends AS f
ON m.id = f.member_one_id
AND f.member_two_id = ?
UNION ALL
SELECT
m.name
FROM
members AS m
INNER JOIN
member_friends AS f
ON m.id = f.member_two_id
AND f.member_one_id = ?
And that is just for a simple query. Just imagine what happens when things get more complex. Indeed, they will explode in your face, and you will start pulling your hair out in the horror of it all.
Yes, there are other ways of writing this using multiple joins, but those would be even more horrible.
Instead, if you store both (A, B) and (B, A) in the database the first query just works. Add to that an index on member_two_id and it will performant to boot.
Sure, it is a bit weird to store it that way, but for the sake of your database and that of your database, please go that route.