database design for notification settings - sql-server

A user can turn on or off
notification settings for his
account, for notifications such as
Changed Account Profile Information,
Received New Message etc
Notification can be sent via email or mobile phone (either push or sms), user can have 1 email only and many mobile phone devices.
Is there any way you would improve the following database design or would you do it differently?
let me know thanks
USER_NOTIFICATION_SETTING
Id
UserId
Notification_SettingCode
NotificationTypeCode
UserDeviceId -- the mobile deviceid
IsEnabled -- true (notification is on), false (notification is off)
NOTIFICATION_SETTING
Code - e.g 1001, 1002
Name -- e.g Changed Account Profile Information, Received New Message etc
NOTIFICATION_TYPE
Code - e.g 1001, 1002
Name -- e.g Email, SMS, Push
USER_DEVICE -- the mobile phone device information
etc...etc...

Or maybe this one which propagates natural keys. This has wider tables, but requires less joins. For example, you can get notifications for a UserName directly from the NotificationQueue.
Or this one, which is good enough if you have phone and email only. So far the simplest -- I think that currently I like this one the best.

What you've done looks pretty good actually. I would out of personal preference do the following:
Eliminate the UserId column on User_Notification_Setting as it should already be on your User_Device table
Get rid of the _s in your table names
Change the Code fields in Notification_Setting and Notification_Type to be Id (even if they are not Identity columns) and then change the foreign key references from other tables to have a more consistent NotificationTypeId field name.
Eliminate the IsEnabled field. The fact that a record exists at the intersection should suffice for having the notification. Deletion of that record means that there is no notification. I can see why you might want to remember that a notification was there at one time and maybe have it there to easily re-enable but I see no information stored at the intersection so deletion is just as good.

Looks good, only a few minor suggestions:
Naming of code fields, use table name then _Code
Add a notification for all changes
There are a couple of things I do not agree with Tahbaza on:
I would leave the user id in, it is then faster to get all notifications for a user
I would leave the isEnabled in, it is then possible to temporarily stop all notifications

Related

Change appengine ndb key

I have a game where I've (foolishly) made the db key equal to the users login email. I did this several years ago so I've got quite a few users now. Some users have asked to change their email login for my game. Is there a simple way to change the key? As far as I can tell I'd need to make a new entry with the new email and copy all the data across, then delete the old db entry. This is the user model but then I've got other models, like one for each game they are involved in, that store the user key so I'd have to loop though all of them as well and swap out for the new key.
Before I embark on this I wanted to see if anyone else had a better plan. There could be several models storing that old user key so I'm also worried about the process timing out.
It does keep it efficient to pull a db entry as I know the key from their email without doing a search, but it's pretty inflexible in hindsight
This is actually why you don't use a user's email as their key. Use ndb's default randomly generated key ids.
The efficiency you're referring is not having to query the user's email to retrieve the user id. But that only happens once on user login or from your admin screens when looking at someones account.
You should rip the bandade off now and do a schema-migration away from this model.
Create a new user model (i.e. UsersV2) and clone your existing user model into it to generate new ids.
On all models that reference it add a duplicate field user_v2 = ndb.KeyProperty(UsersV2) and populate it with the new key.
Delete the legacy user model
You should use the taskqueue to do something like this and then you won't have to worry about the process timing out:
https://cloud.google.com/appengine/articles/update_schema
Alternatively, if you are determined to do this cascading update everytime a user changes an email, you could set up a similar update_schema task for just that user.
I ended up adding a new property to my user model and running a crawler to copy the string key (the email) to that new property. I changed my code search for that property rather then the key string to get a user item. Most of my users still have keys that equal their email, but I can safely ignore them as if the string is meaningless. I can now change a users email easily without making a new recored and my other models that have pointers to these user keys can remain unchanged.

Database Tables - To decouple or not?

Is it better to create tables that store a lot of data that are related to an entity (User for example) or many tables to store said data?
For example:
User Table
Name
Email
Subscription Id
Email Notifications
Permissions
Or
User Table
Name
Email
Subscription Table
User ID
Subscription ID
Notification Table
User ID
Receives?
... etc
Please consider code in this as well, or I would have posted to ServerVault.
From a relational design standpoint what is important is the normal form you're aiming for. In general, if the "column" would require multiple values (subscription_id1, subscription_id2, etc) then it is a repeating group, and that would indicate to you that it needs to be moved to a related table. You've provided very general table and column notes, but taking a cue from the fact that you named "Email Notifications" and "Permissions" with plurals, I'm going to assume that those require related tables.

Database design for opt-in emails

I have a table of users in SQL Server with all the contact details, personal details etc. When each user signs up to my website they will be given the option to opt-in to 5 different types of emails like:
I wish to receive emails about new things
I wish to receive the monthly newsletter
etc etc. I am trying to decide the best way to store this information in a database. My current thinking is to have a seperate table with 5 columns (one for each opt-in) and the value being a bool/bit value.
Since the information wont be required regularly, it will only be required when we want to send mail to user. Are there any better ways / best practices for doing something like this?
The problem with your proposed design is that it becomes difficult to add new email types in the future; you only have 5 now, but what happens when you add a sixth or seventh?.
Instead, I would propose something like:
User Table:
UserID (Primary Key)
User Attributes
EmailTemplate Table
EmailTemplateID (Primary key)
Email Template Attributes
UserEmailTemplates
UserID
EmailTemplateID
You can easily add new templates, and associate them with users.

Any simple approaches for managing customer data change requests for global reference files?

For the first time, I am developing in an environment in which there is a central repository for a number of different industry standard reference data tables and many different customers who need to select records from these industry standard reference data tables to fill in foreign key information for their customer specific records.
Because these industry standard reference files are utilized by all customers, I want to reserve Create/Update/Delete access to these records for global product administrators. However, I would like to implement a (semi-)automated interface by which specific customers could request record additions, deletions or modifications to any of the industry standard reference files that are shared among all customers.
I know I need something like a "data change request" table specifying:
user id,
user request datetime,
request type (insert, modify, delete),
a user entered text explanation of the change request,
the user request's current status (pending, declined, completed),
admin resolution datetime,
admin id,
an admin entered text description of the resolution,
etc.
What I can't figure out is how to elegantly handle the fact that these data change requests could apply to dozens of different tables with differing table column definitions. I would like to give the customer users making these data change requests a convenient way to enter their proposed record additions/modifications directly into CRUD screens that look very much like the reference table CRUD screens they don't have write/delete permissions for (with an additional text explanation and perhaps request priority field). I would also like to give the global admins a tool that allows them to view all the outstanding data change requests for the users they oversee sorted by date requested or user/date requested. Upon selecting a data change request record off the list, the admin would be directed to another CRUD screen that would be populated with the fields the customer users requested for the new/modified industry standard reference table record along with customer's text explanation, the request status and the text resolution explanation field. At this point the admin could accept/edit/reject the requested change and if accepted the affected industry standard reference file would be automatically updated with the appropriate fields and the data change request record's status, text resolution explanation and resolution datetime would all also be appropriately updated.
However, I want to keep the actual production reference tables as simple as possible and free from these extraneous and typically null customer change request fields. I'd also like the data change request file to aggregate all data change requests across all the reference tables yet somehow "point to" the specific reference table and primary key in question for modification & deletion requests or the specific reference table and associated customer user entered field values in question for record creation requests.
Does anybody have any ideas of how to design something like this effectively? Is there a cleaner, simpler way I am missing?
Option 1
If preserving the base tables is important then I would create a "change details" table as a child to your change request table. I'm envisioning something like
ChangeID
TableName
TableKeyValue
FieldName
ProposedValue
Add/Change/Delete Indicator
So you'd have a row in this table for every proposed field change. The challenge in this scenario is maintaining the mapping of TableName and FieldName values to the actual tables and fields. If your database structure if fairly static then this may not be an issue.
Option 2
Add a ChangeID field to each of your base tables. When a change is proposed add a record to the base table with the ChangeID populated. So as an example if you have a Company table, for a single company you could have multiple records:
CompanyCode ChangeID CompanyName CompanyAddress
----------- -------- ----------- --------------
COMP1 My Company Boston <-- The "live" record
COMP1 1 New Name Boston <-- A proposed change
When the admin commits the change the existing live record is deleted or archived and the ChangeID value is removed from the proposed record making it the live record. It may be a little tricky to handle proposed deletions with this option. This option also has the potential for impacting performance of selecting live data for normal usage. However it does save you the hassle of maintaining a list of table names and field names somewhere in your code.
I'm sure others will have some opinions!

DB design for multiple types of entities

I need to develop an application where there will be 4 types of user entities (administrators, partners, companies and clients), each user type has it's own set of details and they all should be able to do common operations like send messages, make payments and so on. These operations should be kept on a single table but they need to reference the exact user despite it's type.
What database design would be more appropriate?
I'd say this is a perfect case for inheritance. Put the common attributes in one table and inherit that to add custom attribute for your different user types.
Chaos answer seems a bit messy to me, alltough it'd be useful if you don't know in advance what the properties you need to store are.
"I would just like to add one more thing, you suggest I have a table per each user type... I prefer this approach however how would I design a schema where I can say that user id 7 (admin) sent a message to user id 537 (client)? Or that a payment was received by user id 70 (company)?"
There is nothing to stop you from doing that. Have a table {sender recipient message(-id)} with primary key all three attributes and two FK {sender} and {recipient}. The FK's refer to the primary key of the table that holds the COMMON attributes of all users.
Now, your next question may be, "but I want a rule to say that no user of type X can directly send a message to any user of type Y".
That is the point where any current IMPLEMENTATION of a (so-called) relational DBMS shows its weaknesses. Even Oracle or DB2 can't do that declaratively. There is simply too very much for me to say about that subject to fit in this response.
BTW You seemed to have taken an interest in my response despite all the downvotes. Really appreciate that.
Have a look at the three ways to do that in the Patterns of Enterprise Application Architecture:
http://martinfowler.com/eaaCatalog/singleTableInheritance.html
http://martinfowler.com/eaaCatalog/classTableInheritance.html
http://martinfowler.com/eaaCatalog/concreteTableInheritance.html
The choice depends on how many properties the 4 types of user entities will be sharing and also on the use cases that your system will require.
user
================
id
user_type_id
name
etc
user_type
================
id
name (admin, partner...)
etc
user_detail
================
id
user_id
user_detail_type_id
value
user_detail_type
================
id
name
user_type_to_user_detail_type
================
id
user_type_id
user_detail_type_id
(maps which user types have which detail types)

Resources