web-dev-qa-db-ja.com

データベースの設計:ユーザーと友達の関係を把握するのに最適なテーブル構造?

あるユーザーが別のユーザーの友達であることを示すデータモデルを設計しようとしています。これは私がこれまでに思いついたものですが、不格好なようです、もっと良い解決策はありますか?

User
=====
Id
Name
etc...

UserFriend
===========
UserId
FriendId
IsMutual
IsBlocked
34
Zachary Yates
UserRelationship
====
RelatingUserID
RelatedUserID
Type[friend, block, etc]

相互関係は列に属さないことに同意します。正規化を解除します。

57
chaos

行く2ユーザーごとに1レコードと提案されたメソッドが提案する余分なメモリを消費しないようにする(各ユーザーに2つのレコードがあるため、必要に応じて2倍)、次のようにすることができます。

  1. テーブル構造:

    USER_RELATIONSHIP {
        user_first_id,
        user_second_id,
        type
    
        primary key(user_first_id, user_second_id)
    }
    
  2. 確認してください:user_first_id < user_second_id

  3. 最も興味深い部分-type:関係の可能なすべての状態の場合、対応する値を作成します。例:

    pending_first_second
    pending_second_first
    friends
    block_first_second
    block_second_first
    block_both
    

あなたが持っているもの:

  1. user_first_id < user_second_idこれにより、指定された2人のユーザー間の関係のレコードが1つだけになることが保証されます。これは、この制約と主キー制約により、他の場所に配置できないためです。
  2. 関係の状態を適切に切り替えることにより、2人のユーザーがそれぞれどのように関係しているかを判断します。 2人のユーザーの間に関係がない場合、レコードはありません。
  3. 2人のユーザー間の関係(および更新)を確認するには、次の1つのクエリを実行します。

    select * from USER_RELATIONSHIP where
        user_first_id = user1_id and
        user_second_id = user2_id;
    

    この列を逆にチェックするorステートメントがなければ、より高速になります。

シナリオ例

  1. no record:関係にありません

  2. pending_first_second:1人目が2人目への友達リクエスト

  3. friends:2番目は友達リクエストを承認しました

  4. no record:ユーザーの1人が他のユーザーを彼の友人から削除しました

このソリューションは、1つのレコードのみを作成、保存、更新するため、メモリと速度の両方の点で効率的です。

39
Artem Novikov

現在、クライアント向けのソーシャルネットワーキングサイトを構築しています。

CREATE TABLE [dbo].[PersonFriend] (
    [Id]                          INT            IDENTITY (1, 1) NOT NULL,
    [Timestamp]                   DATETIME       NOT NULL,
    [ChangeUser]                  NVARCHAR (200) NOT NULL,
    [FriendStatusId]              TINYINT        NOT NULL,
    [Person1Id]                   INT            NOT NULL,
    [Person2Id]                   INT            NOT NULL,
    [Person1RequestTimestamp]     DATETIME       NOT NULL,
    [Person2AcknowledgeTimestamp] DATETIME       NULL
);

各人はPersonテーブルに格納されます(想像してみてください)。 Person1IdおよびPerson2Idフィールドは、personテーブルに対するFKです。私はFriendStatusテーブルにステータスリストを保持し、何かがリクエストされた、受け入れられた、拒否された、無視されたなどをカバーします。タイムスタンプフィールドは、レコードの作成を示すために私の設計では標準です(これは、基本永続クラスで使用されるパターンです) )およびPerson1RequestTimestampに同じデータが含まれているため、このテーブルでその種類が複製されます。また、Person2がリクエストを確認し、それにアクション(FriendStatusIdで示される)を行ったときをキャプチャして、Person2AcknowledgeTimestampに保存します。

この設計の主要な前提の1つは、Person1がPerson2の友情を要求したことです。その友情が受け入れられれば、友情は相互に考慮されます。

9
keithwarren7

私はあなたと同じようなことをしますが、 "IsMutual"フラグを削除します。それが相互である場合、単に逆の値を持つ2番目の行を追加します。行を追加しますが、かなりすっきりします。

5
Jeffrey

私の解決策についてどう思いますか?

3つのテーブルがあります

1 **the user** (id,.etc)
2 **friend_request**(id,flaggerID,flaggedID)
3 **friend**(id,frienderID,friendedID)

あなたはサインインし、フレンドテーブルにいるかどうかを確認します。はいの場合、フレンドリストを作成します(フレンドリスト>フレンドリストにいます)(フレンドリスト>リストフレンドにいます)

リクエストはありますか? (私はflaggedIDにいますか?)彼を知っていますか?そうでない場合は、レコードを削除します。はいの場合、私が報告者に入れられ、報告者が報告されると、リクエストで新しいレコードを作成します。これで、リクエストテーブルの2つのレコード間に相互関係があるため、両方を削除して、フレンドテーブルに配置します。リクエスト/フレンドを簡単に分離できます。

2
csigarena

おそらく、Relationshipテーブルを追加し、そこにリレーションシッププロパティを配置して、UserFriendから参照します。

2
rjurney

おそらく上位にありますが、セマンティックWebを使用してこれをモデル化できます。 FOAF(FOAF Friend of a Friend)形式を使用できます。

2
tuinstoel

私はそれをこのようにしました:

TABLEユーザー

id  name
-----------
1   foo
2   roo
3   shoo
4   mooo

TABLEフレンド関係

id   u_id f_id
--------------
1    1    2
2    2    1
3    3    1
4    1    3

友達リクエストが受け入れられるたびに、逆の方法で挿入1 2 & 2 1と簡単なクエリ:

$ufq=mysql_query("SELECT t1.f_id,t2.id,t2.name FROM friends AS t1, user AS t2 WHERE t1.u_id='$u_id' AND t2.id=t1.f_id ORDER BY t2.name ")or die(mysql_error());
while($fn=mysql_fetch_array($ufq)){
    echo $fn["name"].'<br>';
}
2
aaryadev

あなたは実際に相互の友人がいるかどうかを見つけるために物理的なテーブルが必要ですか?次のようなSQLクエリを実行しないでください。

SELECT U.ID, U.NAME FROM USER U
INNER JOIN USERFRIEND UF
ON U.ID = UF.FRIENDID
WHERE U.ID = (SELECT USER.ID FROM USER
            WHERE USER.ID = friend_id AND USER.ID != your_id);

クエリの結果はすべての共通の友達を返すはずです。

1
ChampionChicken

友情は、古典的な雇用主/上司およびユーザー/配偶者の自己参加シナリオほど明確ではありません。友情は関係ですか、それとも活動ですか?私は後者を無視することについてかなりの批判を受けました。どちらの方法でも、データモデルがどれほど一般的であっても、おそらく複数のテーブルが必要になります。

1
acousticshock

さて、パーティーには遅れましたが、こちらが入札です。

まず、テーブル:

User
-id

Type
-id

Relationship
-user_id_1
-user_id_2
-type_id

ここで、型テーブルをシンプルに保ちたいと思います。したがって、追加するタイプは、単一のユーザーと別のユーザーとの関係のみを表します。双方向の関係を表すことはありません。例えば:

friend
ignored

これにより、新しいタイプを簡単に追加できます。私はすべてのタイプのすべての可能な組み合わせを考えたり作成したりする必要はありません。新しいタイプを追加するだけです。

友情を設定するには、関係テーブルに2つのエントリが必要です。両方のユーザーが自分が友達であることに同意した場合、彼らは友達です。 1人だけが他の人と友達だと言い、もう1人が彼をブロックした場合、彼らは友達ではありません。

クエリは非常に簡単です。 MySQLですべての友達を取得する方法は次のとおりです。

SELECT u.* FROM user u
LEFT JOIN relationship r1 ON u.id = r1.user_id_2
LEFT JOIN relationship r2 ON u.id = r2.user_id_1
WHERE r1.user_id_1 = <my_user_id> # my relationship with them
AND r1.type_id = <friend_type_id> # i say i'm a friend
AND r2.user_id_2 = <my_user_id> # their relationship with me
AND r2.type_id = <friend_type_id> # they say they're friends

また、このアプローチの方が「トランザクションセーフ」だと思います。誰かに友達リクエストを送信し、その後その人をブロックするとします。その人が後で友達リクエストを受け入れる場合、それは問題ではありません。完全に独立しているため、関係の状態は変わりません。

代わりに、双方向の関係を表す単一のタイプがある場合、フレンドがフレンドのリクエストを受け入れた後、関係の新しい状態がどうあるべきかについて、コードで何らかの評価を行わなければなりません。そうしないと、ユーザーのブロックが解除され、そのユーザーがブロックしていたユーザーと友達になる可能性があります。

私はむしろデータベースレベルでこれを処理したいと思います。多くのプログラマーがアプリケーションで作業している場合、誰かがこの問題をどこかで忘れて、見つけにくいバグが作成されるまでにそれほど時間がかかりません。

0

私の理解によると、友情は2人のユーザー(User1とUser2)間の関係の結果です。user1は0人以上のユーザーを友達として持つことができ、その逆はuser2であるため、ジャンクションテーブル「Friend」このような関係を表すために真ん中に来る:

User1 id(int)username(string)

User2 id(int)username(string)

フレンド---- id(int)user1_Id(int)user2_Id(int)active(bool)

User1_Idとuser2_IdはどちらもFrind TableのFKです

私は正しいと思います。

0
Xris

2つのテーブルを作成する必要があると思います。

1.ユーザー
u_id int
u_username文字列
バラフ............

2.友情
fs_id int
relating_id int
related_id int

0
giapnh