Storing Email Unsubscriptions to DB - mysql

I'm working on a product that sends periodic emails to the registered customers, and I would like to implement some kind of an unsubscription mechanism from these emails.
There are about 5 types of emails and a User MySql table that contains all the users. New users are subscribed to all the email types by default, and can unsubscribe from each email type separately.
My question is how should I store these unsubscriptions to the DB, while keeping high performance and scalability and without over-complicating things. Here are a few options that came up, each has its own advantages and disadvantages:
Adding a boolean column on the User table for every report type with a default value of true.
Creating a new Unsubscription table with one-to-one relationship to the User table. Every email type will get a column and every user get a row.
Creating a new Unsubscription table with many-to-one relationship to the User table. Every unsubscription request will create a new row on the table.
Is there a best practice for storing unsubscription information? What are the database-design issues?

option 3. is the most 'normalised' in terms of db schema and means email types can be added without having to do any migrations on the db... it's also the most natural option if you already have a table for storing email types
however you will get better performance with option 1. (no JOINs) at the expense of needing to do a db migration if you add a new email type
option 2. seems to have the inflexibility of 1. while still needing a separate table so would be my least favoured option
A couple of other options to consider:
instead of several boolean fields on the model (option 1.) use a single BitField https://github.com/disqus/django-bitfield to represent unsubscriptions... this has the advantage that you can add new email types without migrating, plus querying is just as fast. removing types you'd have to be careful though
as mentioned above, if you have a table for EmailType already it makes sense to have a many-to-many relation on the User model. But you could use django-denorm to automatically update a BitField on the model which might give the best of both worlds

Related

Is it a good idea to separate the guest_uuid field to a mapping table

The client create a new uuid value to generate and identify a new guest account, and the guest uuid value is now stored in the 'account' table.
'account' table schema: account_id, guest_uuid, other_fields.
guest_uuid is null if the account is not a guest, for example, sign in by facebook.
guest_uuid is only used to check is the account exists. sign in if exists or generate a new guest account if not exists.
Is it a good idea to separate the guest_uuid field from table account to a mapping table called guest_account(guest_uuid, account_id)?
Is it a good idea to separate the guest_uuid field from table account to a mapping table?
Probably not. UUIDs are small enough to be contained with rows. (They don't require storage external to the row like TEXT data types do.) It's not worth the complexity of building and maintaining a new table.
An exception: If each account_id in your application can have multiple uuids, you need this extra table.
Another exception: If you already have millions of rows in your account table, and you are adding functionality requiring this uuid, adding a table may be easier than modifying your account table. Talk to the person who maintains your MySQL server and data.

SQL Table Design Issue

So I am building out a set of tables in an existing database at the moment, and have run into a weird problem.
First things first, the tables in question are called Organizations, Applications, and PostOrganizationsApplicants.
Organizations is a pre-existing table that is already populated with lots of data in regards to an organization's information which has been filled out in another form on another portal. EDIT: I cannot edit this table.
Applications is a table that records all information that a user inputs in the application form of the website. It is a new table.
PostOrganizationsApplicants is basically a copy of Organizations. This is also a new table.
The process goes:
1. Go to website and choose between two different web forms, Form A pertains to companies who are in the Organizations table, and Form B pertains to companies who are not in that table.
2a. If Form A is chosen, a lot of the fields in the application will be auto-populated because of their previous submission.
2b. If Form B is chosen, the company has to start from scratch and fill out the entire application from scratch.
3. Any Form B applicants must go into the PostOrganizationsApplicants table.
Now I am extremely new to SQL and Database Management so I may sound pretty stupid, but when I am linking the Organizations and PostOrganizationsApplicants tables to the Applications table, FK's for the OrganizationsID column and PostOrganizationsApplicantsID columns will have lots of empty spaces.
Is this good practice? Is there a better way to structure my tables? I've been racking my brain over this and just can't figure out a better way.
No, it's not necessarily bad practice to allow NULL values for foreign key columns.
If an instance of an entity doesn't have a relationship to an instance of another entity, then storing a NULL in the foreign key column is the normative practice.
From your description of the use case, a "Form A" Applications won't be associated with a row in Organizations or a row in PostOrganizationsApplicants.
Getting the cardinality right is what is important. How manyOrganizations can a given Applications be related to? Zero? One? More than One? And vice versa.
If the relationship is many-to-many, then the usual pattern is to introduce a third relationship table.
Less frequently, we will also implement a relationship table for very sparse relationships, when a relationship to another entity is an exception, rather than the rule.
I'm assuming that the OrganizationsID column you are referring to is in the PostOrganizationsApplicants table (which would mean that a PostOrganizationsApplicants can be associated with (at most) one Organizations.
I'm also assuming that PostOrganizationsApplicantsID column is in the Applications table, which means an instance of Applications can be associated with at most one PostOrganizationsApplicants.
Bottomline, have a "zero-or-one to many" relationship is valid, as long as that supports a suitable representation of the business model.
Why not just add a column to the Organizations table that indicates that the Organization is a "Post" type of organization and set it for the Form B type of applicants? - then, all your orgs are in one table - with a single property to indicate where they came from.
If you can add a new record to Organizations (I hope you can) just
create FK from Organizations as PK of PostOrganizationsApplicants. So
if Organizations has corresponding record in PostOrganizationsApplicants - it's "Post"!
Thanks everybody, I think I found the most efficient way to do it inspired by all of your answers.
My solution below, in case anyone else has a similar problem...
Firstly I will make the PK of PostOrganizationsApplicants the FK of Organizations by making a "link" table.
Then I am going to add a column in PostOrganizationsApplicants which will take in a true/false value on whether they completed the form from the other portal or not. Then I will ask a question in the form whether they have already done the other version of the form or not. If the boolean value is true, then I will point those rows to the Organizations table to auto-populate the forms.
Thanks again!

What is the best way to organize daily user data in a database?

I am setting up a database using MySQL with the goal of storing data for a potentially large number of unique users. Each user will have some basic data associated with them - a unique username, when they joined the service, how many times they have used the service, in addition to a set of their personal preferences. I am planning on keeping one table called 'Users' dedicated to these fields.
However, there is a bunch of data with a specific schema that will be collected about that user during each session that they use the service. This data includes which user performed this session, the date of the session, what the user did, etc.
My thought process is the following: if I use a single table for users that includes data on each of their sessions, this seems inefficient because there would have to be either a column for each unique session, or a column containing more or less an array or list of sessions. If I wanted to keep this data for an indeterminate number of sessions, then the one-per-column idea would break down, because I believe there is a column limit. Updating an array within a single column also seems to be frowned upon, I think for reasons having to do with preserving the integrity of the data and maintaining the best possible organization.
So it seems like I want two tables, one for users, and another for sessions. Every time anybody completes a session, data about that session will be created as a new row in the 'Sessions' table, and each row would also have a foreign key linking that session to the particular user who completed it.
Is this a correct line of thought? If not, how should I think about this?
Thanks
I would say you're pretty close. You should separate users and sessions, and you're looking at modeling a relationship. Each session only has one user, so it's a one-to-many relationship.
1 User (1 Row in the "Users" table) can have many Sessions (1 Row in the "Sessions" table)
The Foreign Key is the User ID in the Sessions table. This links each unique session (Which will have it's own Session ID I'm assuming) back to a unique User in the Users table.
If you're looking at a massive volume of users, which means a ton of sessions, you may want to consider options on how to help the sessions table not grow to be extremely huge and slow to query. If you're collecting this data on a daily basis, consider that you could "Partition" the table on dates:
Partitioning on DateTime in MySQL
edit: typos

Database model with 3 kind of users

Im thinking about what is the better way to design a database with the following statements:
There are 3 kinds of users (3 differents roles).
They have some common fields, however they have differents fields too.
Solution A:
All user in the same table (some users will have empty fieds depending of their role).
Solution B:
A main table where i will add users and their role. In addition i will create 3 extra tables where i will record with extra fields (depending of the table) and each record will have an id related with the user in the main table.
Solution C: A main table with basic user info, and a second table with the metadata user info where each record means a field of a user. That it's similar than WordPress
Yours is a case of Specialization/Generalization. Since you said User (1, 2, 3) share common properties, it is best to have a General entity - User with all the common attributes.
Then you can Specialize to 3 different types and have the specific attributes to each type.
So, option B is what I think is best solution for your problem.
Option A will cause too many null values and option C is overly complicated.
That depends :-)
Will you ever treat the users the same? E.g. at login time: Will someone just login with a username and this can be any of the three user types? Then you need a user table with a username and a unique index on it. This is solution A or B. I'd prefer B over A, so you can decide which of the fields are nullable for the specific role.
Or will you never deal with a user with an unknown role (such as: a person logs in with a role plus a username, so it suffices to have three different tables each with their own usernames)? This would be three special user tables and no common user table.
Option C would be something easy to implement in order to give users additional attributes, but can become a hassle. Especially when there are obligatory fields and fields that link to other tables (such as a job number that is meant to be the key in the jobs table, but you cannot use a foreign key then). I usually don't take this route, if it is avoidable.

Many-to-One and One-to-One Relationships on Same Two Tables?

I'm designing a database where two fields have a many-to-one relationship, but I also need a one-to-one relationship between them, and I would like some advice on whether there is a better way to do it than what I've got right now.
My tables are accounts and users. An account can have multiple users, but each account can only and must have one owner. A user can be related to only one account.
I have an account field in the users table, which stores the ID of the account the user is related to. In the accounts table, I have an owner field, which stores the ID of the user who owns the account (i.e. the head admin).
I'm using InnoDB so I can make use of foreign keys. The problem is that I can't create an account or a user without the other being created first (due to the restraints of the foreign keys), so I made owner nullable. Now I can create an account with a null owner, then create the user, and finally set the owner on the account to the user.
Is this acceptable, and is there a better way?
Here are some possible other ways I've come up with, and my thoughts on each:
Have a boolean owner field in the users table. Since every account can only have one owner, this way seems less than ideal because I'd have to ensure only one user per account has the attribute set to true.
Have a third table called owners. This seems like more overhead and more work for no good reason since it's effectively the same as having an owner field in the users table.
How I have it now makes the most sense to me, but it's a little awkward having to set a null owner until I create the user, and then coming back to set it after the fact.
I'd appreciate any input you can give me. Thanks!
This question is similar, but there's no mention of foreign keys: Designing Tables: One to many and one to one at same time?
In general is a bad idea if your schema cannot be sorted topologically, i.e. if you cannot establish an ordering where a table only refers to tables preceding it in the ordering. This sort of "layered" dependency is also a very nice property to have for example for software modules (you have a problem if two modules depends on each other).
In your case you have user that refers to account and account that refers to user so clearly there's no way to find a topological ordering.
One standard solution in this case is to introduce a separate table e.g. "role" where you have three columns: user, account and role. The column role can be either "owner" or "guest".
The fact that you know that (given the current requests) an account must have one and only one owner, or that a user must be listed in one and only one account are not IMO rules that are really pertinent to the domain of "users" and "accounts".
You can implement those rules easily, but structuring your data so that you have no other possibility is IMO a mistake. You should aim to model the domain, not the specific rules... because people will change their mind about what those rules are.
Can you conceive a user with two accounts? Can you conceive an account with multiple owners/admins? I can... and this means that most probably quite soon this will be a request. Structuring the data so that you cannot represent this is looking for troubles.
Also when you have cyclical dependencies in the model your queries will be harder to write.
A very common case is for example to try to represent a hierarchical part list database using just one table with a "parent" field that points to the table itself... much better is having two tables instead, part and component, where component has two references to part and and a quantity.
Your solution is fine.
If you're uncomfortable with the owner column being nullable, you could rely on some magic user record (perhaps with an id of zero) which would be the "system user". So newly created accounts would be owned by user-zero, until their ownership was suitably redefined. That seems smellier than allowing accounts to have a null owner, to me, anyway.
For the current requirement to have only one account per user
alter table UserAccount add constraint un_user_account unique(UserID);
and when the requirement changes to many-to-many, drop the constraint
alter table UserAccount drop constraint un_user_account;
For the one owner only, simply enforce that on the application level.