Symmetric relationships

Hi,
I’m building an application where you can have friends like in
myspace. Only if two people agree to be friends, a friendship relation
should be established. If they agreed, it should be an undirected (aka
symmetric, bidirectional)
graph.
I don’t want to keep two entries for each friendship like in the
following table:
table friendships
parent | child
user1 | user2
user2 | user1

I hope you understand what I mean. I want that if anybody of the two
friends quit friendship, the relationship between the two also gets
deleted.

Thanks.

What type of queries do you need to be able to do after this
relationship is set up? For example

Do Pam and Jeff have a friendship?
List all the friends of Pam?
List all the people who are not friends of Pam or Jeff?

The best solution will depend on how you want to get to the data.

steve

Most basically I just want to query the friends of Pam.
If Pam and Jeff are friends, i want to get
Pam as friend of Jeff
and Jeff as friend of Pam.

For this I would have to keep two database entries for each
friendship, like in the following example:
user_id | friend_id
id_of_pam | id_of_jeff
id_of_jeff | id_of_pam

I’d like to do it with one, but I don’t think there is an elegant
solution, or is it?

A wish of mine also would be to get the shortest connection between
person A and person B, like in xing.com (single pair shortest path
problem in graph theory), but I have no idea how to do that, and it’s
not a necessity.

Etherway, not having to keep two entries for each friendship (then you
had also to monitor when a friendship gets deleted to also delete the
other way round) would be favorable for this problem too.

On Jun 11, 5:45 pm, Steve R. [email protected]

Thanks for your advice, but unfortunately I would also like to select
all friends of Pam at once.

On Jun 11, 10:36 pm, Steve R. <rails-mailing-l…@andreas-

Most basically I just want to query the friends of Pam.
If Pam and Jeff are friends, i want to get
Pam as friend of Jeff
and Jeff as friend of Pam.

If you only want to be able to say is Pam a friend of Jeff then you
could assign each user a unique prime number and store the multiple of
the primes in a separate ‘friendship’ table. But that won’t help you
list all the friends of Pam (unless you don’t mind iterating over every
entry in the table).

So, what exact queries do you want to be able to do?

steve

Thanks for your advice, but unfortunately I would also like to select
all friends of Pam at once.

I can’t think of a way of doing this with only one table entry. I’m
surprised because I thought I would be able to. It’s an interesting
problem and I’ll pass it on to some colleagues.

steve

No progress I’m afraid.

You are aware that what you want is handled by Rails using
has_and_belongs_to_many relationships? But it does use two entries in a
table for each relationship, you just don’t have to actually handle the
table yourself.

steve

Steve R. wrote:

I did this in the following way (YMMV):

class Person << AR::B
has_many :relation_tos,
:class_name => ‘Relationship’,
:foreign_key => ‘related_from’
has_many :relation_froms,
:class_name => ‘Relationship’,
:foreign_key => ‘related_to’
has_many :related_tos,
:through => :relation_tos,
:source => :relatee,
:select => “modtypes., relationships.relationship_type,
relationships.notes" # This gets the key join table details as well
has_many :related_froms,
:through => :relation_froms,
:source => :relator,
:select => "modtypes.
, relationships.relationship_type,
relationships.notes” # This gets the key join table details as well

def related_types
related_froms.find(:all) + related_tos.find(:all)
end

The downside is, there’s two db queries to get the related people. I did
this ages ago, in my early days on Rails, so haven’t really looked to
see whether it can be improved.

Hope this helps

Chris
p.s. It’s not really a person class, since that sort of relationship
isn’t reflexive – e.g. think of uncle-nephew relationship.

http://autopendium.com
Stuff about old cars

How about using sql? avoiding habtm or hm :through?

so given a table

table friends
int inviter_id
int Invitee_id
bool accepted

And only one entry per friendship.

then find all friends using…

find_by_sql(
‘SELECT p.* FROM people p, friends f WHERE f.accepted = ‘t’ AND
( (f.invitee_id = #{id} AND p.id = f.inviter_id) OR (f.inviter_id =
#{id} AND p.id = f.invitee_id) )’
)

I haven’t tested this, but seems it should work in both directions.