实施用户事件ORM模型的阻止日期

时间:2016-01-15 23:01:51

标签: sql ruby-on-rails postgresql date activerecord

继续Find entry where value does not intersect with other value

我有一个应用程序(Ruby on Rails,ActiveRecord,Postgresql),它使用用户表,日期表和事件表来跟踪用户及其事件以及发生这些事件的日期。事件有很多日期,用户可以通过不同的表格登录事件。

我在这里工作的功能是让用户能够阻止某些日期,以便我以后可以找到1)X []中没有任何日期被阻止的用户,以及2)用户的所有事件,包括用户已阻止的任何日期。

我目前正在使用原始方法,日期存储为用户,事件和运算符的简单字符串:

User.where.not("string_to_array(blocked_dates, ',') && string_to_array(?, ',')", "date1,date2...")

我想知道是否有任何解决此问题的面向数据库的方法比比较数组重叠有更好的性能。

Postgres版本:psql(PostgreSQL)9.4.5

表基数:

用户 - 事件:一对多(如果用户是状态管理员)

用户 - 事件:通过一个名为邀请的不同表格(如果用户是状态客户端)多对多

事件 - EventDate:一对多

\ d用户

的语句
id                     | integer                     | not null default nextval('users_id_seq'::regclass)
created_at             | timestamp without time zone | 
updated_at             | timestamp without time zone | 
email                  | character varying(255)      | not null default ''::character varying
encrypted_password     | character varying(255)      | not null default ''::character varying
...
and other 100 or so fields like first_name, last_name ...

来自\ d events

的语句
id                    | integer                     | not null default nextval('events_id_seq'::regclass)
title                 | character varying(255)      | 
description           | text                        | 
user_id               | integer (this refers to another type of user, capable of creating events, not the type of user we are referring to here)                    | 
project_status        | character varying(255)      | default 'create_project'::character varying
created_at            | timestamp without time zone | 
updated_at            | timestamp without time zone | 
due_time              | timestamp without time zone | 
... 
and other fields such as address, referrer number...

来自\ d event_dates

的语句
id             | integer                     | not null default nextval('event_dates_id_seq'::regclass)
title          | character varying(255)      | 
event_id       | integer                     | 
created_at     | timestamp without time zone | 
updated_at     | timestamp without time zone | 
date           | character varying(255) (I need to explicitly store a string value)     | 
formatted_date | timestamp without time zone (String value is converted to the timestamp on save) | 
Indexes:
   "event_dates_pkey" PRIMARY KEY, btree (id)
   "index_event_dates_on_event_id" btree (event_id)

来自新​​字段的语句\ d blocked_date_periods

id             | integer                     | not null default nextval('blocked_date_periods_id_seq'::regclass)
user_id        | integer                     | 
created_at     | timestamp without time zone | 
updated_at     | timestamp without time zone | 
start_date     | timestamp without time zone | 
end_date       | timestamp without time zone | 

1 个答案:

答案 0 :(得分:0)

这是我选择的解决方案。诀窍是对用户和blocked_date_periods表使用left outer join(ruby命令eager_load),并且包括那些在连接表中的start_date字段为NULL的用户,显然是因为他们没有与自己关联的任何阻塞日期对象。我使用的查询:

User.eager_load(:blocked_date_periods).
  where("blocked_date_periods.start_date is null OR 
    not tsrange(
      blocked_date_periods.start_date - '00:59:59'::interval,
      blocked_date_periods.end_date + '00:59:59'::interval
    ) @> ?::timestamp", 
  Date.parse(DATE_STRING)).count

我必须在开始和结束日期之前添加和减去1小时,因为查询由于某种原因不希望包含确切的结束日期,因此12-26-2015期间不包括12-22 -2015至2015年12月12日由于某种原因我尚未理解。

出于某种原因,我不喜欢这个解决方案,并且想知道是否有比我更好更快的查询。