Laying out a database schema for a calendar application - database

I want to write a calendar application. It is really recurring items that throw a wrench in the works for the DB schema. I would love some input on how to organize this.
What if a user creates an event, and inputs that it repeats everyone Monday, forever? How could I store all that in the database? I can't create infinite events. Do I simply put a table in there that holds the relevant info so I can calculate where all the events go? If so, I would have to calculate them every time the user views a new part of the calendar. What if they page through the months, but they have a ton of recurring items?
Also, the schema needs to handle when a user clicks an item and says "Edit this one in the sequence" not all items in the sequence. Do I then split the one item off of the sequence?
Update 1
I have not looked at iCal at all. To be clear, I think saving the info that allows you to calculate the recurring items, and splitting off any that differ from the sequence is a great way to store it to be able to transfer it. But I think that in an application, this would be too slow, to do the date math all over the place.

I have been struggling with the same problem, and I was actually toying with the "cache table" idea suggested above, but then I came across an alternative (suggested here) that doesn't seem to have been represented yet.
Build a table containing all events
EventID (primary key)
Description
StartDate
PeriodType - days, weeks, months, years
PeriodFreq - # of days, weeks, etc between events
EndDate
... other attributes that can be modified
Then add a table for exceptions to these events. This table uses a composite key, made up of the EventID that maps to the event table, and an instance ID to pick the particular event in the series.
EventID (key)
InstanceID (key)
InstanceDate - the modified date of the exception
IsCancelled - a flag to skip this date when traversing the series
... other attributes that can be modified
It seems to keep the event table normalised, and avoids splitting up series to handle exceptions.

I recently created a calendar application and this was one of the many challenges that I faced.
I eventually came up with a semi hack-ish solution. I created an event_type column. In that column, I had either: daily, weekly, monthly, or yearly. I also had a start_date and an end_date columns. Everything else was handled in the actual backend code.
I never tried to split an event if a user edited only one event. It wasn't necessary in the situation. However, you could split an event by changing the end_date of the first, creating a new event with a new start_date and the end_date of the original, and finally, a new event for the one you just chose to edit. This process would end up creating 3 events.
Hack-ish, I know. I couldn't think of a clever way to handle this problem at the time.

Hold the recurring item in the events table as normal, but flagged as recurring with the appropriate start/ end dates.
If the user modifies a single instance of the appointment, just create a new event, perhaps with a 'parentId' equal to the recurring event's id.
Build logic that causes the calendar to override any recurring events on a particular day with events with matching parent IDs.
Your question about performance is basically the old speed vs. storage issue. I really don't think the calculation required would exceed the space requirement for storing so many appointments. Just read up on database optimization- indexing etc.

Could you bridge the two worlds with a "cache" table, in which you pre-compute the next X days worth of events?
So three tables:
recurring_event_specs
one_time_events
cached_recurring_events
For any part of the calendar within X days of today, your query will UNION one_time_events and cached_recurring_events.
Then you would only have to do on-the-fly date calculations if the user tried to look at a part of the calendar more than X days in the future. I imagine you could find a sane X that would cover the majority of normal use.
The cached_recurring_events table would need to be updated whenever a user adds a new recurring event -- and possibly once a day offline, by a cron-job/scheduled-task. But only on days when no new recurring event has been created.

Why not use Google Calendar as a database for this calendar application by relying on Google Calendar's API for storing and retrieving calendar events?
The Calendar API is a REST API that can be accessed through explicit HTTP calls; the API exposes most of the features available in the Google Calendar Web interface, so your calendar application can as much functionality as Google Calendar does (a lot of functionality!!!).
Your application need only implement OAuth 2.0 for Google APIs, which can be made easy using a single sign-on service like Auth0 to provide the appropriate access tokens. Then, your calendar application can use these tokens in conjunction with the Calendar API to provide seamless storage and retrieval of calendar events in a JSON format.
Users create events within their own "New Calendar." This calendar is shared with you in the form of a gmail account dedicated to this application - the application's gmail account.
Basically, Google Calendar becomes your database, whereby you can have the application's gmail account not only store all of your application's events, but also allow you to view and edit these events with an intuitive interface.

The best way to do this is to store a standards based recurrence pattern string (iCal).. and leave blank if it's a single event. There are a few APIs that can parse the recurrence pattern and create event objects that you can bind to UI elements.... none of the occurrences need ever be stored in the database, only the initial event (occurrence)..

Couldn't you store the events per day with start and end time? It will generate a lot of data for events that happen everyday (maybe go non-relational for this) but it will make querying easier and it will be possible to make exceptions (f.e. the event place burned down, or employees are striking). To generate the days for the event I would suggest to implement that in the front-end derived on some ICal-ish pattern.

Related

Firestore: handling concurrency with booking app

I've currently got a bookings and a bookable collection. Each document in bookings holds a date range (check-out and check-in) and an array of references to bookable documents.
I'm a bit stumped at how to guarantee two overlapping bookings for the same bookables aren't written at the same time. From what I understand I can't technically lock a collection via something like a transaction, so I'm wondering what my options are (perhaps restructuring how I'm storing data, etc).
Any pointers or advice would be much appreciated.
EDIT:
Say User A wants to make a booking for the same two items as User B does and for the same time range. They both load the booking UI at around the same time and confirm their selection.
Prior to creating a new document inside the bookings collection for each of their requests, the app would perform a get query to check for any overlaps and if none exist insert the new booking documents. That fraction of time between the app's check for overlaps across the booking collection and the creation of new documents is what seems to open up a window for inconsistencies (e.g. potentially allowing two documents with overlapping time ranges and items to be created).
Could a transaction help prevent a new document being written to a collection based the existance of other documents in that collection that fit a specific criteria?
To prevent users from accidentally overwriting each other's data, you'll want to use a transaction.
To prevent users from intentionally overwriting each other's data, you'll want to use security rules. Key to this is to use the information that you want to be unique as the ID of the documents.
So say you identify time slots by the date and start time, you could have a document ID "20210420T0900". If a user is trying to write to that document when it already exists, you can reject that write in the security rules of your database.
I am facing the exact same problem, and here is my best option at the moment....
I need a collection of all booking (bookingscollection), regardless of date, time, resource booked etc. This collection is usabale in many parts of my UI, as I list upcoming bookingss etc.
I need to avoid writes being made to this collection, where there is an overlap.
I am considering adding an additional collection, where each document descibes the bookings for a specific resource on a specific day (lockcollection). It could be a doc, with the resource id, the date it covers and an array of start,stop times of booking already made.
Then when considering adding a new booking to my bookingscollection, I would make a transaction to the relevant document in the lockcollection, see if there is an overlap in which case I would fail, and if not, I would add the new intervall to the lock document within the transaction.
Once this succeed, I know that I can just plainly add the booking to the booking collection, as the lock is already there....
Similar logic would be applied to the procedure of deleting or changing bookings.
This idea is new to me, but I wanted to sahre, so I can hear your inputs....?

how to bulk add calendar events with powerapps

i'm messing about with powerapps and attempting to build a small app that adds all my exams into my school's calendar as this will save me (and other students) a lot of time.
at the moment i have already managed to get all the required data from the excel file that contains all exams with their dates, locations, times and much more irrelevant information. this data is filtered to only include the exams for me (and technically all other engineering students if i make it public)
i've stored it in a collection and have no problem using it.
the issue is the outlook/office365 connector as im not shure it can do what i'd like it to do.
Office365.V2CalendarPostItem(calendarSelect.Selected,test.'Cursus Omschrijving',test.'Datum/Date',test.Tot,{Location:test.'Locatie/Location'})
i've put up a calendar selection dropdown thing as i dont know if all calendars are the same so you can select the right one. calendarSelect.Selected is the result of that. test.'Cursus Omschrijving' is the title of the exam. the date bit is, well, the date and start time, and test.Totis the end time.
the issue is Office365.V2CalendarPostItem expects only one item at a time really. powerapps complains about it recieving a table and not text or a date as it expects.
Do any of you know if it is even possible to do what im planning(bulk adding calendar items) or is powerapps not capable of this and i need to switch over to a more powerful language?

Ways to design a digest email implementation?

I'm looking for some thoughts about how to design a digest email feature. I'm not concerned about the actual business code; instead I'd like to focus on the gist of it.
Let's tackle this with a known example: articles. Here's a general overview of some important features:
The user is able to choose the digest frequency (e.g. daily or weekly);
The digest only contains new articles;
"New articles" are to be considered relative to the previous digest that was sent to a specific user;
I've been thinking about the following:
Introduce per-user tracking of articles previously included in a digest and filter those out?
Requires a new database table;
Could become expensive when the table contains millions of rows;
What to do in case of including multiple types of models in the digest? Multiple tracking tables? Polymorphic table? ...?
Use article creation dates to include articles between current date and the chosen digest frequency?
Uses current date and information already present in the database, so no new tables required;
What happens when a user changes from daily to weekly emails? He could receive the same article again in the weekly digest. Should this edge case be considered? If so, how to mitigate?
For some reason the creation date of an article is being updated to today, positively triggering the date comparison again. Should this edge case be considered? If so, how to mitigate?
Or can you think of other ways to implement this feature?
I'm eager to learn your insights.
You can make an additional table that will contain information about digest subscription by each user. This way gives the ability to make a database design cleaner and more universal because mailing is a separate logical module. Aside from that, the additional table gives the ability to expand stored data about digest subscription easy in future. For example:
With help usage of this table, you would manage data easy. For example, you can select all recipient of daily digest:
SELECT *
FROM digest_subscription
WHERE interval_type = 'daily'
AND last_date_distribution <= NOW()
or select all recipient of the weekly digest
SELECT *
FROM digest_subscription
WHERE interval_type = 'weekly'
AND last_date_distribution <= NOW() - INTERVAL 7 DAY
Condition by interval type and compare the last date distribution by rule "equal or less" give the ability to avoid problems of untimely sending of emails (for example technical failures on a server, etc.)
Also, you can make correct articles list with help information of the last data distribution. Usage of the last data distribution gives the ability to avoid problems of interval change. For example:
SELECT *
FROM articles
WHERE created_at >= <the last date distribution of the user>
Of course, you don't avoid the problems of updated creation date. But you should minimize the reasons for that happening. For example, your code can update the modification date but your code shouldn't modify the creation date.

Recurring Events Database Model

I've being searching for a solution for recurring events, so far I've found two approaches:
First approach:
Create an instance for each event, so if the user has a daily event for one year, it would be necessary 365 rows in the table.
It sounds plausible for a fixed time frame, but how to deal with events that has no end date?
Second approach:
Create a Reccuring pattern table that creates future events on runtime using some kind of Temporal expression (Martin Fowler).
Is there any reason to not choose the first approach instead of the second one?
The first approach is going to overpopulate the database and maybe affect performance, right?!
There's a quote about the approach number 1 that says:
"Storing recurring events as individual rows is a recipe for disaster." (https://github.com/bmoeskau/Extensible/blob/master/recurrence-overview.md)
What do you guys think about it? I would like some insights on why that would be a disaster.
I appreaciate your help
The proper answer is really both, and not either or.
Setting aside for a moment the issue of no end date for recurrence: what you want is a header that contains recurrence rules for the whole pattern. That way if you need to change the pattern, you've captured that pattern in a single record that can be edited without risking update anomalies.
Now, joining against some kind of recurrence pattern in SQL is going to be a great big pain in the neck. Furthermore, what if your rules allow you to tweak (edit, or even delete) specific instances of this recurrence pattern?
How do you handle this? You have to create an instance table with one row per recurring instance with a link (foreign key) back to the single rule that was used to create it. This let's you modify an individual child without losing sight of where it came from in case you need to edit (or delete) the entire pattern.
Consider a calendaring tool like Outlook or Google Calendar. These applications use this approach. You can move or edit an instance. You can also change the whole series. The apps ask you which you mean to do whenever you go into an editing mode.
There are some limitations to this. For example, if you edit an instance and then edit the pattern, you need to have a rule that says either (a) new parent wins or (b) modified children always win. I think Outlook and Google Calendar use approach (a).
As for why having each instance recorded explicitly, the only disastrous thing I can think of would be that if you didn't have the link back to the original recurrence pattern you would have a heck of a time cancelling the whole series in one action.
Back to no end date - This might be a case of discretion being the better part of valour and using some kind of rule of thumb that imposes a practical limit on how far into the future you extend such a series - or alternatively you could just not allow that kind of rule in a pattern. Force an end to the pattern and let the rule's creator worry about extending it at whatever future point it becomes necessary.
Store the calendar's event as a rule rather than just as a materialized event.
Storing recurring event materialized as a row is a recipe for disaster for the apparent reason, that the materialization will ideally be of infinite length. Since endless length table is not possible, the developer will try to mimic that behavior using some clever, incomprehensive trick - resulting in erratic behavior of the application.
My suggestion: Store the rules and materialize them and add as rows, only when queried - leading to a hybrid approach.
So you will have two tables store your information, first for storing rules, second, for storing rows materialized from any rule in the rules' table.
The general guidelines can be:
For a one-time event, add a row to the second table.
For a recurring event, add a row to the first table and materialize some of into the second table.
For a query about a future date, materialize the rules and save them in the second table.
For a modification of a specific instance of a recurring event, materialize the event up till the instance you want to modify, and then modify the last instance and store it.
Further, if the event is too far in the future, do not materialize it. Instead save it as a rule also and execute it later when the time arrives.
Plain tables will not be enough to store what you are trying to save. Keeping this kind of information in the database is best maintained when supported with Stored Procedures for access and modifications.
from the answers in the blog post and answers here:
1- eat DB storage and memory with these recurrences (with no need) , with the extreme case of "no-end date"
2- impact performance (for query / join / update / ...)
3- in case of update (or generally in any case you need to handle the recurrence set as a set not as individual occurrences) , you will need to update all rows

Design Database for repeated events

I'm trying to design a database table for storing events that occurs at different intervals,
--daily, eg. everday around 10am
--every tue,mon and wed of a week,
--monthly, eg. 1st of every month
--twice a month, eg. 3rd and 4th of every month
How can I achieve this with simple database design. Any help, suggestion is appreciated. Thanks in advance!
You are mixing up the UI with the backend. You need to create the following tables:
intervals(interval_id, name, repeat_time_span)
events(event_id, interval_id, name, created)
You need to implement the CRUD to handle intervals and events insertion, modification, deletion and view. You need to link UI controls (like a form and a grid) to enable user interaction with the events and intervals and to implement any advanced logic regarding those.

Resources