我正在尝试按meeting rooms
列出可用的office_id
,其中可用性取决于bookings
与selected_start_time
和selected_end_time
>
这是我的模式
defmodule MyApp.Context.Booking do
schema "bookings" do
field :start_time, :utc_datetime
field :end_time, :utc_datetime
belongs_to :meeting_room, MyApp.Context.MeetingRoom, foreign_key: :meeting_room_id
timestamps()
end
end
defmodule MyApp.Context.MettingRoom do
schema "meeting_rooms" do
belongs_to :office, MyApp.Context.Office, foreign_key: :office_id
has_many :bookings, MyApp.Context.Booking
timestamps()
end
end
defmodule MyApp.Context.Office do
schema "offices" do
field :name, :string
has_many :meeting_rooms, MyApp.Context.MeetingRoom
timestamps()
end
end
我已经尝试使用fragment
的内容。如果在选定的时间内没有创建booking
,则此方法有效。为booking
创建meeting_room_id = 1
后,即使仍然有另一个可用的meeting_room
?
meeting_room_id = 2
此语句将检查重叠的def list_available_meeting_rooms(office_id, selected_start_time, selected_end_time) do
query = from office in Office,
where: office.id == ^office_id,
join: meeting_rooms in assoc(office, :meeting_rooms),
where: fragment("NOT EXISTS (SELECT * FROM bookings WHERE start_time < ? AND ? < end_time)",
^selected_end_time, ^selected_start_time),
select: meeting_rooms
Repo.all(query)
end
和start_time
。您可以在这里Algorithm to detect overlapping periods
end_time
预期结果应返回可用fragment("NOT EXISTS (SELECT * FROM bookings WHERE start_time < ? AND ? < end_time)", ^selected_end_time, ^selected_start_time)
的列表
例如:
meeting_rooms
offices
id | name
1 | Office 1
meeting_rooms
id | office_id
1 | 1
2 | 1
3 | 1
4 | 1
按bookings
id | start_time | end_time | meeting_room_id
1 | 2019-09-17 03:00:00Z | 2019-09-17 04:00:00Z | 1
2 | 2019-09-17 03:00:00Z | 2019-09-17 04:00:00Z | 2
和office_id
和start_time = 2019-09-17 03:00:00Z
查询可用会议室列表时,它应仅返回end_time = 2019-09-17 04:00:00Z
id 3和4。
我如何获得这种结果?
任何一种帮助都会很棒。预先感谢!
答案 0 :(得分:0)
您选择from Office
,这意味着您可能在Office
上应用条件,而您可能想在meeting_rooms
上应用条件。 AFAICT,您根本不需要Office
,但实际上您需要加入bookings
,因为您在片段中使用了它。
所以有点像这样。
query =
from meeting_room in MeetingRoom,
join: bookings in assoc(meeting_room, :bookings),
where: meeting_room.office.id == ^office_id,
where: fragment(...),
select: meeting_room
Repo.all(query)
答案 1 :(得分:0)
我相信@ aleksei-matiushkin的回答是正确的,而且我不确定为什么它不起作用。但是在不使用片段的情况下达到相同结果的另一种方法是条件连接,然后检查null值,我尚未对其进行测试,但以下内容应完全相同:
MeetingRoom
|> join(:left, [mr], mrb in assoc(mr, :bookings), on:
mrb.meeting_room_id == mr.id and
mrb.start_time < ^selected_end_time and
mrb.end_time > ^selected_start_time
)
|> where([mr], mr.office_id == ^office_id)
|> where([mr, mrb], is_nil(mrb.id))