Separate Users Across 2 Tables? - mysql

I'm building a Ruby on Rails application, I'm separating two sets of users:
Buyers
Sellers
Currently someone built the database with both under a Users table with:
t.string "user_type", default: "buyer", null: false
There are some additional data I will need to hold for Sellers and there is also a few features/pages I want Sellers to have access to, but not Buyers.
For example I want to hold bank details so I can pay Sellers what we are paid by Buyers (we hold payments for a few days to ensure safe transaction). So the additional data may be:
Account Number
Sort Code
We do not need to store this data for Buyers since they use Stripe for payment.
Do we include the data on the current Users table? or do we create a new Sellers table that is linked to the Users table?

You can use one table and have the differences in the models. As users, they will share many common features, e.g. authentication during sign_in, change password, etc.
class User < ActiveRecord::Base
...
end
class Buyer < User
def buyer_specific_method_one
...
end
end
class Seller < User
def seller_specific_method_one
...
end
end
And add a string field named 'type' to the user table. See Single Table Inheritance.

There is a number of options you can use. Not necessarily one, some combinations are possible:
Factor out differences (bank details?) into separate models with one-one relationships with User
You can make them one-many later if you need to, one seller may provide info for multiple banks
You do not restrict your users from being both buyer and a seller simultaneously (if you want)
If these details are not needed on every single request, the performance penalty is not too big
Single Table Inheritance
Alter the string column user_type to be just type, then make two more models without a table (--no-migration), inheriting not from ActiveRecord::Base, but from User, so they inherit its table for persistence
Your users table will need to have all the columns from all subclasses
Any User subclasses (like Buyer) will be defined as a User with certain type ("Buyer")
Serialize attributes that you'll be processing on app level only, not in the database
You'll need to create a text-type column for each collection of serialized attributes that you want
You'll only be restricted by the format of serializer, not database columns and types, it allows you to store arbitrary data there
You can define a custom serializer that outputs custom objects (maybe even models?)
Be extra careful not to allow users to arbitrarily edit collections
Make sure you only need serialized data from already loaded objects, contrary is a design flaw

Related

best practice for designing system with multiple user type

We have a system with two main roles: service provider and customer. The provider side is users like doctors, nurses, and caregivers. The customer side is just the customer. all user types contain some common data and some uncommon data. in the current system, we have a table for each user type, and for common data, we have User table. currect system ERD is:
https://s4.uupload.ir/files/screenshot-20210710165449-1007x662_tpwd.png
in the current system, we have a lot of tables and we think about reducing them. our vision is to bring all user types in a single table called User and instead of a lot of tables, we have more columns. of course in some users, we have empty cells that do not belong to this user type.
I have 4 questions:
is it ok to bring customers and providers to a table like User?
what is the optimal number of columns in a table?
load a row with a lot of columns OR relation between different tables?
provider type should be a separate table or can be an enum?
It is best to put all users in single table. So when you check login there is less place to do mistake. When selecting user you dont need to use SELECT * FROM... You can use SELECT id, username, name FROM...
Dont put too many columns, if there is some data which you dont need when searching or displaying users, you can create helper table "user_meta" with dolumns user_id, meta_key, value where user_id and meta_key are primary key
Answered by first 2 answers
Provider type should be enum if there will not bee needs to expand with additional types.

Which one is better, defining two tables, or having a boolean flag to determine the type of a user

I'm designing the database for one of my projects, and we have two types of users, a normal user (default), and a bushiness user, they have identical attributes but differ on abilities, for instance.
A business user can post a job, whereas the normal user can only apply to jobs and nothing more, which one is the preferred way of doing so.
Method 1
Define two different tables: will cost storage space since both users have identical attributes
or
Method 2
Having a boolean flag to determine the type of user ex is_business_account attribute, which might bloat the code with if, else conditions.
This can be solved with roles but do i need to define such table for roles or ?
Thank you for your time
When creating entities, you don't want to have multiple entities that are really the same. In your case, you have Users as an entity (table) and one of the attributes is whether or not they are a business user. As part of your program, when the user signs in, you check the user against 1 table to log in and which set of functions to display.

Integrating payment methods in db schemas

I have a requirement where I need to create A database where a user can have multiple payment methods and against those multiple payment methods multiple transactions can be processed.
I have created the following schema
WHY THESE TABLES:
user: This table contains information about the user. Ex: First Name, Last Name, Email etc
user_payment_method: Since a single user can have multiple payment methods I created a table to identify all the payment methods he has so that i can reference them in the transactions table and could know on exactly which payment method the transaction was made on.
transaction: This table contains all the data about all the transactions. Ex: Time, user_id, user_method_id, amount etc
payment_method: This table acts as a junction table(pivot table) to reference all the payment methods that could exist. Since all payment methods have different details I cannot make a single table for this.
specific payment method tables: Tables like bank_transfer and paypal contain the specific details the user has about that payment method. Ex: paypal keys or bank account numbers
THE PROBLEM
I am stuck at creating a relationship between payment_method and specific payment method tables.
How do I reference different payment methods within a single column in the payment_method table. Do i create a junction(pivot) table for each specific payment method?
EDIT: If anyone has a simpler different approach please let me know too I am open to all ideas.
I would probably simplify the schema as follows:
user <- transaction -> payment method
The payment method would include your PayPal and Bank Transfer, which should not be different tables.
Generally, you should think of your payment method as a type of transaction.
When constructing a database, you look for the tables where the real action is. In this case it’s the transaction table. You can recognise it from an entity diagram as the one with the foreign keys pointing outward. In this case, you can say that a transaction belongs to a user and is of a certain type.
The transaction table would have the actual payment details, such as the date, amount, transaction number etc.
You could also have a table of preferred payment details. That would give you something like this:
user <- transaction -> payment method
<- preferred ->
Remember, that preferences can change, so the data from the preferred table should be copied into the transaction table, to allow the preferences to change later.
Needless to say, we presume that you are taking all the proper precautions regarding passwords, account details and other sensitive data …
The problem can be categorised as modelling inheritance. You have n payment methods, each with different (user specific) properties. The simplest is TPH table per hierarchy: put all the user properties for all payment methods on the user_payment_method table. There are other options covered here. Forget about pivot table: you're modelling a DB schema and you only need tables and columns. Think about what you need to store, how you need to retrieve it, and the importance of storing each fact once only.

Storing orders with different product types, each having a unique set of parameters, in MySQL

I am working on an e-commerce website that will sell cloths but also provide a way to book a service, like manicure. I am trying to create a single shopping cart, to which users will add both. The user should have a single shopping cart and a single total to pay for in the end. The problem is how should I store these in the database?
Cloths will have size and colour as params, while the services will have the date and time, when the user wants to get the service. Storing all these parameters in a single table order_items doesn't look too wise, while storing params as a serialized string doesn't feel any better.
What is the most common way of storing this data together?
I also work for a e-commerce store and we ahd the same problem. Easiest is have a "cart" and "cart_item" table respectively, where the shared columns between the products are stored, eg: price, quantity etc.
Then you have a table "cart_item_voucher" and "cart_item_product" which save the details specific to the voucher or product. Each one will reference "cart_item" with the "cart_item_id" foreign key.
Also "cart_item" will have a type field and from there you can distinguish the difference.

Database Design: User Profiles like in Meetup.com

In Meetup.com, when you join a meetup group, you are usually required to complete a profile for that particular group. For example, if you join a movie meetup group, you may need to list the genres of movies you enjoy, etc.
I'm building a similar application, wherein users can join various groups and complete different profile details for each group. Assume the 2 possibilities:
Users can create their own groups and define what details to ask users that join that group (so, something a bit dynamic -- perhaps suggesting that at least an EAV design is required)
The developer decides now which groups to create and specify what details to ask users who join that group (meaning that the profile details will be predefined and "hard coded" into the system)
What's the best way to model such data?
More elaborate example:
The "Movie Goers" group request their members to specify the following:
Name
Birthdate (to be used to compute member's age)
Gender (must select from "male" or "female")
Favorite Genres (must select 1 or more from a list of specified genres)
The "Extreme Sports" group request their member to specify the following:
Name
Description of Activities Enjoyed (narrative form)
Postal Code
The bottom line is that each group may require different details from members joining their group. Ideally, I would like anyone to create a group (ala MeetUp.com). However, I also need the ability to query for members fairly well (e.g. find all women movie goers between the ages of 25 and 30).
For something like this....you'd want maximum normalization, so you wouldn't have duplicate data anywhere. Because your user-defined tables could possibly contain the same type of record, I think that you might have to go above 3NF for this.
My suggestion would be this - explode your tables so that you have something close to 6NF with EAV, so that each question that users must answer will have its own table. Then, your user-created tables will all reference one of your question tables. This avoids the duplication of data issue. (For instance, you don't want an entry in the "MovieGoers" group with the name "John Brown" and one in the "Extreme Sports" group with the name "Johnny B." for the same user; you also don't want his "what is your favorite color" answer to be "Blue" in one group and "Red" in another. Any data that can span across groups, like common questions, would be normalized in this form.)
The main drawback to this is that you'd end up with a lot of tables, and you'd probably want to create views for your statistical queries. However, in terms of pure data integrity, this would work well.
Note that you could probably get away with only factoring out the common fields, if you really wanted to. Examples of common fields would include Name, Location, Gender, and others; you could also do the same for common questions, like "what is your favorite color" or "do you have pets" or something to that extent. Group-specific questions that don't span across groups could be stored in a separate table for that group, un-exploded. I wouldn't advise this because it wouldn't be as flexible as the pure 6NF option and you run the risk of duplication (how do you predetermine which questions won't be common questions?) but if you really wanted to, you could do this.
There's a good question about 6NF here: Would like to Understand 6NF with an Example
I hope that made some sense and I hope it helps. If you have any questions, leave a comment.
Really, this is exactly a problem for which SQL is not a right solution. Forget normalization. This is exactly the job for NoSQL document stores. Every user as a document, having some essential fields like id, name, pwd etc. And every group adds possibility to add some fields. Unique fields can have names group-id-prefixed, shared fields (that grasp some more general concept) can have that field name free.
Except users (and groups) then you will have field descriptions with name, type, possible values, ... which is also very good for a document store.
If you use key-value document store from the beginning, you gain this freeform possibility of structuring your data plus querying them (though not by SQL, but by the means this or that NoSQL database provides).
First i'd like to note that the following structure is just a basis to your DB and you will need to expand/reduce it.
There are the following entities in DB:
user (just user)
group (any group)
template (list of requirement united into template to simplify assignment)
requirement (single requirement. For example: date of birth, gender, favorite sport)
"Modeling":
**User**
user_id
user_name
**Group**
name
group_id
user_group
user_id (FK)
group_id (FK)
**requirement**:
requirement_id
requirement_name
requirement_type (FK) (means the type: combo, free string, date) - should refers to dictionary)
**template**
template_id
template_name
**template_requirement**
r_id (FK)
t_id (FK)
The next step is to model appropriate schema for storing restrictions, i.e. validating rule for any requirement in any template. We have to separate it because for different groups the same restrictions can be different (for example: "age"). You can use the following table:
**restrictions**
group_id
template_id
requirement_id (should be here as template_id because the same requirement can exists in different templates and any group can consists of many templates)
restriction_type (FK) (points to another dict: value, length, regexp, at_least_one_value_choosed and so on)
So, as i said it is the basis. You can feel free to simplify this schema (wipe out tables, multiple templates for group). Or you can make it more general adding opportunity to create and publish temaplate, requirements and so on.
Hope you find this idea useful
You could save such data as JSON or XML (Structure, Data)
User Table
Userid
Username
Password
Groups -> JSON Array of all Groups
GroupStructure Table
Groupid
Groupname
Groupstructure -> JSON Structure (with specified Fields)
GroupData Table
Userid
Groupid
Groupdata -> JSON Data
I think this covers most of your constraints:
users
user_id, user_name, password, birth_date, gender
1, Robert Jones, *****, 2011-11-11, M
group
group_id, group_name
1, Movie Goers
2, Extreme Sports
group_membership
user_id, group_id
1, 1
1, 2
group_data
group_data_id, group_id, group_data_name
1, 1, Favorite Genres
2, 2, Favorite Activities
group_data_value
id, group_data_id, group_data_value
1,1,Comedy
2,1,Sci-Fi
3,1,Documentaries
4,2,Extreme Cage Fighting
5,2,Naked Extreme Bike Riding
user_group_data
user_id, group_id, group_data_id, group_data_value_id
1,1,1,1
1,1,1,2
1,2,2,4
1,2,2,5
I've had similar issues to this. I'm not sure if this would be the best recommendation for your specific situation but consider this.
Provide a means of storing data as XML, or JSON, or some other format that delimits the data, but basically stores it in field that has no specific format.
Provide a way to store the definition of that data
Provide a lookup/index table for the data.
This is a combination of techniques indicated already.
Essentially, you would create some interface to your clients to create a "form" for what they want saved. This form would indicated what pieces of information they want from the user. It would also indicate what pieces of information you want to search on.
Save this information to the definition table.
The definition table is then used to describe the user interface for entering data.
Once user data is entered, save the data (as xml or whatever) to one table with a unique id. At the same time, another table will be populated as an index with
id where the xml data was saved
name of field data is stored in
value of field data stored.
id of data definition.
now when a search commences, there should be no issue in searching for the information in the index table by name, value and definition id and getting back the id of the xml/json (or whatever) data you stored in the table that the data form was stored.
That data should be transformable once it is retrieved.
I was seriously sketchy on the details here, I hope this is enough of an answer to get you started. If you would like any explanation or additional details, let me know and I'll be happy to help.
if you're not stuck to mysql, i suggest you to use postgresql which provides build-in array datatypes.
you can define a define an array of varchar field to store group specific fields, in your groups table. to store values you can do the same in the membership table.
comparing to string parsing based xml types, this array approach will be really fast.
if you dont like array approach you can check out xml datatypes and an optional hstore datatype which is a key-value store.