I have schema design problem which I am not 100% sure if my assumptions are correct.
So the requirements are:
- I need to have 2 different type of user, anonymous and public.
- A user can have both anonymous and public profile.
- A public and anonymous user can follow anonymous and public.
- Anonymous user and public user must not be identifiable by clients. Which means if I know public user I shouldn't be able to fetch anonymous profile details vice versa.
I first come up with idea:
User (id, anon_id,public_id)
AnonymousUser(id(PK,FK),nickname)
PublicUser(id(PK,FK),nickname,fullname,phone,is_phone_registered)
RelationShip(id,follower_id(FK-User),following_id(FK-User))
Tweet(id, author_id(FK-User),text)
In this design I could split users into two. However, if we know the tweet's author id we are not able to understand if it's send by public or anonymous account. And also the same problem exist in Relationship too, we are not able to understand if follower/following is anonymous or public. The solution might be adding 2 more fields to Relation clarify follower/following type ie. follower_type/following_type and 1 more field to Tweet author_type.
Another solution which I felt more correct is
User(id(PK),nickname,fullname,phone,is_phone_registered,public)
In this design I can have both anonymous and public profiles in same table. And records would look like:
id | nickname | fullname | phone | is_phone_registered | public |
---|---|---|---|---|---|
123 | slayer | John Doe | +1 90 123 123 12 12 | true | NULL |
312 | vendetta | NULL | NULL | false | 123 |
And public field should not be visible to clients so I am pretty much achieving my goals on security side of things.
Sorry for my ignorance I am having NoSql background and in sql world I feel like I need achieve:
- Single responsibility in tables
- Get rid of a lot of redundant null's
- Feels like self referencing column is an anti-pattern, which is public field is referencing to other rows id.
All suggestions are welcomed.
Best Answer
Based on your requirements, a user can have a public and anonymous account - however, those must be kept separate, which necessitates a exclusive subtype so different accounts have different
UserIds
/NickNames
. But we also need to maintain a relation between the public and anonymous accounts. Since a Public user can't be owned by an anonymous account, the relationship is reserved for the anonymous user subtype.The last requirement is to create a check to ensure the exclusivity between
PublicUser
andAnonymousUser
is maintained - this can be done through a function and check constraint (SQL Server, Sybase) or anAFTER INSERT
trigger (everything else). Basically, after the row is inserted into one of the subtype tables, the trigger will queryUser
to get theUserTypeCd
. If the code matches, the transaction is allowed to commit. If not, the transaction is rolled back.I'm working under the assumption an anonymous user must be associated with a public user. If this is not the case, we implement
PublicUserId
as an optional column like so:Other notes:
Is_Phone_Registered
is just an indicator ifPhoneNumber
isNULL
. If this is the case, there is no need to store this value, it can be derived.Id
columns, you need to name them within the context of each entity, soUserId
,TweetId
, etc.Relationship
, there is no need for theId
column, your primary key is(FollowingId
,FollowerId)
(both FK references back toUser
). No additional columns are needed.