jdi*_*n04 6 javascript sql postgresql
我已经阅读了大约 20 篇关于重复事件数据建模选项的不同帖子,并最终确定了一个实现,但在最终细节方面仍然需要一些帮助。
首先,这里描述了我要完成的任务和要求:
显然,我的应用程序的很大一部分是基于调度的。具体来说,我系统的这个组件允许企业客户安排家庭服务的约会。这些约会可以是单次发生的,也可以是重复发生的。虽然这些约会是典型的,因为它们有开始/结束时间等,但每个约会也有与之相关的数据。该数据可能包括诸如入住时间、退房时间、备注等内容。
为了存储重复约会,我的选择是要么在预定时间点生成每个实例,然后在这些实例运行时在数据库中生成新实例,要么即时计算要返回的这些实例。我最终选择了后者,因为我认为从长远来看,该实现更清洁,更易于维护。
话虽如此,根据这篇文章的见解,我选择将我的重复模式存储为 RRULE 字符串,并使用 PGV8 和rrule.js库进行任何计算。那篇文章提到了物化视图的使用(阅读了它们,但从未使用过),但我不确定它是否适用于我的情况,因为我必须在定期约会更改或创建时重新生成这些。似乎我还需要为每个业务创建一个实体化视图,并且不确定这会如何影响存储/性能,因为可能有 1000 个业务。如果您对此有任何见解,请告诉我。
这个想法是有一个表,Appointment,其中包含与约会的实际日期、时间和重复(如果适用)相关的数据。它将至少包含以下字段:
然后,第二个表,AppointmentData,将存储有关约会本身的任何元数据。例如,它可能包含以下字段:
在AppointmentData当实例只会产生Appointment实际上是由服务提供商启动。
一般来说,我只需要能够在任何给定时间检索 31 天或更少的约会(除了检索单个实例)。也就是说,我的想法是能够将开始和结束日期传递给数据库,该数据库将找到该范围内所有约会的单次出现。此外,对于包含重复模式的任何记录,我将使用我的 PLV8 函数返回该范围内的日期列表。该rrule.js 库有一个函数可以返回重复模式 ( rule.between(new Date(2012, 7, 1), new Date(2012, 8, 1))) 的所有日期。
这是我有点磕磕绊绊的地方。现在我在数据库中有一个可以动态计算重复日期的函数,我有点不清楚如何将这些与单个事件“融合”在一起并将它们作为单个结果集返回。请注意,对于每个重复出现的实例,我还需要返回表中的所有列Appointment,例如serviceID.
如果有什么不清楚的,请告诉我。
提前致谢!
对于那些想要做类似事情的人,我提出了以下建议:
首先,使用 rrule.js 从 iCAL RRule 字符串生成递归的函数:
CREATE OR REPLACE FUNCTION public.generate_recurrences(
recurrence_pattern CHARACTER VARYING,
start_date date,
end_date date)
RETURNS SETOF TEXT
LANGUAGE plv8
IMMUTABLE STRICT
AS $function$
// parse the RRULE string
var rule = RRule.fromString(recurrence_pattern);
// return all occurrences between start date and end date
var recurrences = rule.between(start_date, end_date);
for(var i = 0; i < recurrences.length; i++) {
plv8.return_next(new Date(recurrences[i]).toISOString());
}
$function$
Run Code Online (Sandbox Code Playgroud)
最后,该函数获取非重复约会的任何实例,并将它们与上述函数生成的重复实例合并:
CREATE OR REPLACE FUNCTION recurring_events_for(
for_business_id INTEGER,
range_start DATE,
range_end DATE
)
RETURNS SETOF appointment
LANGUAGE plpgsql STABLE
AS $BODY$
DECLARE
appointment appointment;
recurrence TIMESTAMPTZ;
appointment_length INTERVAL;
BEGIN
FOR appointment IN
SELECT *
FROM appointment
WHERE business_id = for_business_id
AND (
recurrence_pattern IS NOT NULL
OR (
recurrence_pattern IS NULL
AND scheduled_start_time BETWEEN range_start AND range_end
)
)
LOOP
IF appointment.recurrence_pattern IS NULL THEN
RETURN NEXT appointment;
CONTINUE;
END IF;
appointment_length := appointment.scheduled_end_time - appointment.scheduled_start_time;
FOR recurrence IN
SELECT *
FROM generate_recurrences(
appointment.recurrence_pattern,
range_start,
range_end
)
LOOP
EXIT WHEN recurrence::date > range_end::date;
CONTINUE WHEN recurrence::date < range_start::date AND recurrence::date > range_end::date;
appointment.scheduled_start_time := recurrence;
appointment.scheduled_end_time := recurrence + appointment_length;
RETURN NEXT appointment;
END LOOP;
END LOOP;
RETURN;
END;
$BODY$;
Run Code Online (Sandbox Code Playgroud)
上面的结果是一个结果集,其中包含两个单一事件的约会记录,但也动态生成重复事件的完整约会记录(只是日期)。
| 归档时间: |
|
| 查看次数: |
1100 次 |
| 最近记录: |