активный запрос записи в rails 4 и postgres

У меня 2 модели

Class Ride
  has_many :trips

  #state (string: active or expired)
end

Class Trip
  #date (Date attribute)
  scope :active, -> (start_at = Date.today) { where("trips.date >= ?", [Date.today, start_at].max) }  
end

Ежедневно мне нужно обновлять состояние на Поездках с активным состоянием, имея все поездки с атрибутом даты ‹Date.today как выполнить это в 1 запросе? я могу заархивировать такой результат, используя:

Ride.with_active_state.select{|r| r.trips.active.size ==0}

но он делает запросы huje для подсчета поездок, например:

    [1] pry(main)> Ride.with_active_state.select{|r| r.trips.active.size ==0}
   (7.3ms)  SELECT f_geometry_column,coord_dimension,srid,type FROM geometry_columns WHERE f_table_name='rides'
  Ride Load (1.6ms)  SELECT "rides".* FROM "rides" WHERE (rides.workflow_state = 'active')
   (2.9ms)  SELECT f_geometry_column,coord_dimension,srid,type FROM geometry_columns WHERE f_table_name='trips'
   (1.3ms)  SELECT COUNT(*) FROM "trips" WHERE "trips"."ride_id" = $1 AND (trips.date >= '2013-09-24')  [["ride_id", 9]]
   (0.7ms)  SELECT COUNT(*) FROM "trips" WHERE "trips"."ride_id" = $1 AND (trips.date >= '2013-09-24')  [["ride_id", 10]]
   (0.7ms)  SELECT COUNT(*) FROM "trips" WHERE "trips"."ride_id" = $1 AND (trips.date >= '2013-09-24')  [["ride_id", 11]]
   (0.7ms)  SELECT COUNT(*) FROM "trips" WHERE "trips"."ride_id" = $1 AND (trips.date >= '2013-09-24')  [["ride_id", 12]]
   (0.8ms)  SELECT COUNT(*) FROM "trips" WHERE "trips"."ride_id" = $1 AND (trips.date >= '2013-09-24')  [["ride_id", 13]]
   (0.8ms)  SELECT COUNT(*) FROM "trips" WHERE "trips"."ride_id" = $1 AND (trips.date >= '2013-09-24')  [["ride_id", 14]]
   (0.5ms)  SELECT COUNT(*) FROM "trips" WHERE "trips"."ride_id" = $1 AND (trips.date >= '2013-09-24')  [["ride_id", 15]]
   (0.5ms)  SELECT COUNT(*) FROM "trips" WHERE "trips"."ride_id" = $1 AND (trips.date >= '2013-09-24')  [["ride_id", 16]]
   (0.5ms)  SELECT COUNT(*) FROM "trips" WHERE "trips"."ride_id" = $1 AND (trips.date >= '2013-09-24')  [["ride_id", 17]]
   (0.5ms)  SELECT COUNT(*) FROM "trips" WHERE "trips"."ride_id" = $1 AND (trips.date >= '2013-09-24')  [["ride_id", 18]]
   (0.5ms)  SELECT COUNT(*) FROM "trips" WHERE "trips"."ride_id" = $1 AND (trips.date >= '2013-09-24')  [["ride_id", 19]]
   (0.5ms)  SELECT COUNT(*) FROM "trips" WHERE "trips"."ride_id" = $1 AND (trips.date >= '2013-09-24')  [["ride_id", 20]]

....


person Danil    schedule 23.09.2013    source источник


Ответы (1)


Добавьте области на Ride с помощью предложений group и having. Он проверит количество всех будущих поездок заездов и вернет заезды с нулевым счетом.

Class Ride

  scope :active_state, where(state: "active")
  scope :with_nonactive_trips, -> (start_date = Date.today){ joins(:trips).
                                    group("rides.id").
                                    having( ["sum(trips.date > ?) = 0",start_date] ) }

end

Ride.active_state.with_nonactive_trips
# returns All the rides with state == active, alteast one trip and having no trips with date > Date.today

Используя lambda, поскольку он был у вас в активном прицеле в Trip. Я предполагаю, что вам нужно использовать дату, отличную от Date.today, для некоторых запросов.

person tihom    schedule 23.09.2013
comment
Поездка может иметь 2 поездки, одна с истекшей датой, а другая с датой в будущем. в этом случае его не следует выбирать в этом запросе ... - person Danil; 24.09.2013
comment
Некоторое объяснение того, почему вам нужно использовать лямбда для второй области, может быть хорошей идеей. - person mu is too short; 24.09.2013
comment
и поездка всегда имеет как минимум 1 поездку (просрочена или нет, но существует всегда) - person Danil; 24.09.2013
comment
scope :with_nonactive_trips, -> (start_date = Date.today){ includes(:trips). group("rides.id, trips.id").references(:trips). having( ["sum(cast(trips.date >= ? as int)) = 0",start_date] ) } это помогло мне. Спасибо за помощь! - person Danil; 24.09.2013
comment
@Danil будьте осторожны, используя includes, так как он создает внешнюю таблицу соединений и будет медленным запросом, если размеры таблиц большие. Если joins выполняет эту работу за вас, я бы предложил использовать его вместо includes. Вы можете использовать профилировщик, чтобы увидеть разницу во времени выполнения запросов. - person tihom; 24.09.2013
comment
с объединениями он выбирает неправильные записи. не знаю почему. если я изменяю соединения, чтобы включить, он выбирает записи, которые я ожидаю - person Danil; 24.09.2013