如何在Elixir中查询空或无关联

时间:2019-09-16 15:10:20

标签: elixir phoenix-framework ecto

我正在尝试按meeting rooms列出可用的office_id,其中可用性取决于bookingsselected_start_timeselected_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_idstart_time = 2019-09-17 03:00:00Z查询可用会议室列表时,它应仅返回end_time = 2019-09-17 04:00:00Z id 3和4。

我如何获得这种结果?

任何一种帮助都会很棒。预先感谢!

2 个答案:

答案 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))