具有异常的重复事件的数据库设计

Database design for recurring events with exceptions

我正在构建一个需要 store/manage 不同类型事件的系统。为简单起见,我将专注于设计日历(我构建的东西略有不同,但日历是一个很好的类比,而且很容易推理)。我想听听可能的 database/schema 设计想法。

问题描述

我有一个包含不同类型事件的日历(为简单起见,假设只有一种类型的事件:任务)。用户可以为特定日期添加新事件、编辑(更改一些细节,如标题或移至另一个日期)或删除。可以有 one-time 事件和重复事件(具有不同类型的重复:每 X 天、每月的第 15 天、每周的星期一;有点像简单的 cron)。当用户移动重复事件时,此事件的所有其他实例都以相同的方式移动(例如:+3 天)。重要部分:重复发生的事件可以有例外。因此,例如,假设我有一个每 7 天重复一次的重复事件 A。但我想将它的日期更改为下周,所以它被分配到星期五而不是星期二,之后它仍然会在星期二发生。 "exception" 事件在移动 "parent" 事件时不应受到影响。

此外,每个重复发生的事件都可以有额外的信息,仅与 1 个特定实例相关,例如:我有相同的重复发生事件 A 每 7 天重复一次,我想为本周实例添加一条注释,上面写着"X",我想为下个月的事件 A 添加另一个注释,上面写着 "Y" - 这些字段仅对单个实例可见。

想法

具有常规 one-time 事件的系统非常简单,所以我不会讨论它,只关注重复发生的事件。

1. 一种可能的解决方案是类似于 OOP 的解决方案:我可以有一个 Event "class" 字段,例如 start_dateend_date(可以是 null)、recurrence_type(类似于枚举,可能的值为 EVERY_X_DAYSDAY_OF_WEEKDAY_OF_MONTH)和 recurrence_value(比如 7)。当用户添加新的重复事件时,我只是在数据库中创建这样的 Event 。当用户想要更改此事件的 1 次发生时,我将新条目添加到 type/class MovedEvent 的数据库中,"inherits" 来自 Event 且日期不同,并且具有附加字段 related_to 指向与其相关的 EventID(或 UUID,如果你愿意的话)。但与此同时,我需要跟踪所有 MovedEvents(否则我会在同一周显示 2 个事件),所以我需要有一个数组 moved_events of IDs 指向所有 MovedEvents。 缺点:每次我想显示日历时,我需要从 moved_events 获取 Event 和 select 所有事件,如果我会有很多感动的事件。

2. 另一个想法是将每个事件存储为单独的记录。 IMO 这是一个糟糕的想法,但我只是提到它是因为它有可能。 缺点:每次我想编辑主要事件(例如:我想将事件从发生"every 7 days"更改为"every 9 days")我需要更改每一个事件的发生。不过,"Exceptions"(更改单个实例)更容易。

SQL/NoSQL?比例详情

我在我的项目中使用 PostgreSQL,但我对 NoSQL 数据库有基本的了解,如果它们更适合解决此类问题,我可以使用它。

规模:假设我有 5000 个用户,每个用户平均有 150 个 events/week,其中 40% 可以是 "exceptions"。因此我想把这个系统设计得高效。

类似问题和其他资源

我刚刚开始阅读 Martin Fowler 的 "Recurring Events for Calendars" (http://martinfowler.com/apsupp/recurring.pdf) 但我不确定它是否适用于我的问题,如果适用,如何根据此设计数据库模式文件(欢迎提出建议)。

有类似的问题,但我没有看到任何提及 "exceptions"(更改 1 个事件实例而不影响其他),但也许有人会发现这些链接有用:

抱歉,问题很长,我想把问题描述清楚。然而,我觉得这很混乱,所以如果你有其他问题,我很乐意提供更多细节。同样,我想听听可能的 database/schema 设计想法以及任何其他建议。谢谢!

使用 iCalendar 规则和 ExDates

如果它是重复发生的事件,只需存储 start/end 事件的日期时间以及 RRules 和 ExDates。

使用物化视图预先计算即将发生的实际事件,比如接下来的 30 天或 365 天。

由于您使用的是 Postgres,您可以在 pg 函数中使用现有的 python、perl 或 javascript RRule 库(例如 dateutil)来计算未来事件规则和日期

更新:查看 pg_rrule 扩展名:https://github.com/petropavel13/pg_rrule