Эффективный запрос Postgresql для сортировки встреч в простом календаре с помощью Rails - PullRequest
2 голосов
/ 14 октября 2019

TL; DR: У меня есть база данных с тысячами встреч, которые имеют атрибуты start_time и end_time. Учитывая диапазон дат (26 мая - 31 июня), как мне найти каждую встречу, которая происходит в этом диапазоне?

Назначение с 15 мая по 25 мая НЕ включено
Назначение изС 15 мая по 29 мая необходимо включить
Необходимо включить встречу с 1 июня по 3 июня
Необходимо включить встречу с 20 июня по 5 июля
Необходимо назначить встречу с 15 мая по 15 июлявключено (самая сложная часть проблемы)
Встреча с 1 июля по 4 июля НЕ включена


У нас есть модель встреч, в которой есть start_time и end_time. Если встреча происходит в какие-либо дни во время ежемесячного просмотра, ее необходимо загрузить в переменную экземпляра (@monthly_appointments), чтобы гем simple_calendar мог отображать ее в календаре.

Пример: встреча с 1 июнядо 3 июня должен отображаться, когда пользователь просматривает календарь «Июнь 2020». Встреча с 15 мая по 15 июля также должна появляться каждый день в течение июня.

На каждой стороне календарных дат есть 6-дневное заполнение, так как если неделя начинается в субботу (1 июня)вы увидите 26 июня - 31 мая в июньском календаре (см. рисунок).

Можно подумать, что это так же просто, как сказать: «Если встреча начинается или заканчивается в течение данного месяца, добавьтеэто назначение для переменной экземпляра. Однако существуют случаи, когда встреча начинается 15 мая и длится 60 дней, до 15 июля. Встреча не начинается и не заканчивается в июне, но она все равно должна отображаться в календаре.

Изначально мы говорили пользователям: «встречи не могут длиться дольше 6 месяцев», а затем мы использовали этот поиск, где мы предполагали, «если встреча началась в течение последних 6 месяцев, включите ее в переменную итогда мы позволим гему календаря отработать все остальное. "

@monthly_appointments = current_user.appointments.includes(:pet).where(start_time: (Time.zone.now).beginning_of_month - 6.months..(Time.zone.now).end_of_month + 6.days))

Однако этот запрос иногда может сэкономить 3000+назначений в переменной, когда, на самом деле, есть только 50-70 назначений, которые ДОЛЖНЫ быть показаны за этот месяц.

Итак, я написал следующий код, и он успешно находит встречи, которые происходят как минимум в один день в течение календарного периода. Он сравнивает диапазон ежемесячного календаря (26 мая .. 31 июня) и диапазон встречи (1 июня. 3 июня), а затем ищет любые даты, встречающиеся в обоих массивах (&). Это работает хорошо, но это занимает немного времени, потому что ему нужно загрузить ВСЕ встречи для пользователя (тысячи), а затем просмотреть каждое из них, чтобы увидеть, произойдет ли это в течение этого месяца.

У кого-нибудь есть какие-нибудь другие умные решения этой проблемы? Я уверен, что что-то там существует, но я еще не нашел это. Спасибо!

month_dates = ((Time.zone.now.beginning_of_month - 6.days)..(Time.zone.now.end_of_month + 6.days)).to_a

@monthly_appointments = current_user.appointments.includes(:pet).select do |appt|
  #create array of appointment dates and see if it intersects any of the monthly date array
  appt_dates = (appt.start_time.to_date..appt.end_time.to_date).to_a
  (month_dates & appt_dates).present?
end
Models:
Appointment(start_time, end_time, note, user_id, pet_id)

Pet
has_many appointments

User
has_many appointments

Here's an example.

carley = Pet.find(12)

Appointment.create(pet_id: carley.id, start_time: "May 15 2020 06:00:00", end_time: "July 15 2020 06:00:00"...)

Когда я просматриваю календарь на июнь 2020 года, это назначение должно отображаться каждый день.

enter image description here

1 Ответ

1 голос
/ 14 октября 2019
from_time = '2019-05-26'.to_date
to_time = '2919-06-30'.to_date

@appointments = Appointment.where('start_time <= ? AND end_time >= ?', to_time, from_time)

Выше будут выбраны все встречи, включенные или перекрывающие диапазон from_time и to_time, а также встречи, которые начинаются до диапазона и заканчиваются после диапазона.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...