This question is around how should I design a database, it can be relational / nosql databases, depending on what will be the better solution
Given a requirement where you'll need to create a system that will involve a database to track "Company" and "User". A single user always only belong to one company
- A user can only belong to one company
- A company can have many users
The design for "Company" table is quite straightforward. Company will have the following attributes / columns: (let's keep it simple)
ID, COMPANY_NAME, CREATED_ON
First scenario
Simple & straight forward, users all have the same attribute, so this can be easily done in relational style, user table:
ID, COMPANY_ID, FIRST_NAME, LAST_NAME, EMAIL, CREATED_ON
Second scenario
What happen if different companies want to store different profile attribute for their user. Each company will have a defined set of attributes that would apply to all users of that company.
For example:
- Company A wants to store: LIKE_MOVIE (boolean), LIKE_MUSIC (boolean)
- Company B wants to store: FAV_CUISINE (String)
- Company C wants to store: OWN_DOG (boolean), DOG_COUNT (int)
Approach 1
the brute force way is to have a single schema for the user and let them have nulls when they dont belong to the company:
ID, COMPANY_ID, FIRST_NAME, LAST_NAME, EMAIL, LIKE_MOVIE, LIKE_MUSIC, FAV_CUISINE, OWN_DOG, DOG_COUNT, CREATED_ON
Which is kinda nasty because you will end up with a lot of NULLS and user rows that have columns that are irrelevant to them (ie. all users belonging to Company A has NULL values for FAV_CUISINE, OWN_DOG, DOG_COUNT)
Approach 2
a second approach, is to have "free form field":
ID, COMPANY_ID, FIRST_NAME, LAST_NAME, EMAIL, CUSTOM_1, CUSTOM_2, CUSTOM_3, CREATED_ON
Which would be nasty on its own since you have no idea what custom fields are, the data type will not be reflective of the values stored (eg. we'll store int value as VARCHAR).
Approach 3
I have looked into PostgreSQL JSON field, in which case you will have:
ID, COMPANY_ID, FIRST_NAME, LAST_NAME, EMAIL, CUSTOM_PROFILE_JSON, CREATED_ON
In this case, how would you be able to apply different schemas to a user? A user with Company A will have schema that looks like
{"LIKE_MOVIE":"boolean", "LIKE_MUSIC": "boolean"}
While a user with Company C will have a different schema:
{"OWN_DOG ":"boolean", "DOG_COUNT": "int"}
How should I solve this issue? How can I design database properly to allow for this flexible schema for a single "object" (User) based on the relationship they have (Company)?
relational solution? nosql solution?
Edit: I've also thought about a "CUSTOM_PROFILE" table which will essentially store user attributes in rows rather than columns.
There are 2 problems with this approach:
1) The data grows per user grow as rows rather than columns - and this mean to get a full picture of the user, a lot of joins need to be done, multiple joins to the "custom profile" table on the different custom attributes
2) The data value is always stored as VARCHAR to be generic, even if we know the data is supposed to be integer or boolean etc