Rails加入了关联限制

max*_*max 6 postgresql activerecord ruby-on-rails

我正在尝试对所有站点进行查询,并加入Measures

但我只想要最新的措施(由created_at DESC排序),因为一个站有数千个措施.

我试过了

Station.joins(:measures).limit(1) 
Run Code Online (Sandbox Code Playgroud)

但这只是限制了电台.

附加信息:

车站有很多措施

措施属于Station

我已经阅读了Active Records文档,并且只有关于在关联中使用where条件的信息.

该应用程序仅针对Postgres,SQL已被接受.


编辑:添加除schema.rb之外:

  create_table "measures", force: true do |t|
    t.integer  "station_id"
    t.float    "speed"
    t.float    "direction"
    t.float    "max_wind_speed"
    t.float    "min_wind_speed"
    t.float    "temperature"
    t.datetime "created_at"
    t.datetime "updated_at"
    t.float    "speed_calibration"
  end

  add_index "observations", ["created_at"], name: "index_observations_on_created_at", using: :btree
  add_index "observations", ["station_id"], name: "index_observations_on_station_id", using: :btree

  create_table "stations", force: true do |t|
    t.string   "name"
    t.string   "hw_id"
    t.float    "latitude"
    t.float    "longitude"
    t.float    "balance"
    t.boolean  "offline"
    t.string   "timezone"
    t.integer  "user_id"
    t.datetime "created_at"
    t.datetime "updated_at"
    t.string   "slug"
    t.boolean  "show",                         default: true
    t.float    "speed_calibration",            default: 1.0
    t.datetime "last_observation_received_at"
  end
Run Code Online (Sandbox Code Playgroud)

添加 这是目前正在使用的hackhish代码:

def all_with_latest_measure
  if user_signed_in? && current_user.has_role?(:admin)
    stations = Station.all.load
  end
  stations ||= Station.where(show: true).load

  if stations.size
    ids = stations.map { |s| s.id }.join(',')
    where = "WHERE m.station_id IN(#{ids})" unless ids.empty?
    measures = Measure.find_by_sql(%Q{
    SELECT DISTINCT ON(m.station_id, m.created_at)
      m.*
    FROM measures m
    #{where}
    ORDER BY m.created_at DESC
    })

    stations.each do |station|
      # Setup has_many relationship between station and Measure
      # Prevents n+1 queries
      measure = Measures.find { |m| m.station_id == station.id  }
      if measure
        measure.station = station
        station.latest_measure = measure
      end
    end
  end
end
Run Code Online (Sandbox Code Playgroud)

Kom*_*owy 5

我相信在 Rails 4 中,您可以在关联上应用范围:

class Stations
  has_many :measures, -> { order('created_at DESC').limit(1)  }
end
Run Code Online (Sandbox Code Playgroud)

然后:

2.0.0-p353 :008 > Station.first.measures
  Station Load (0.1ms)  SELECT "stations".* FROM "stations" ORDER BY "stations"."id" ASC LIMIT 1
  Measure Load (0.1ms)  SELECT "measures".* FROM "measures" WHERE "measures"."station_id" = ? ORDER BY created_at DESC LIMIT 1  [["station_id", 1]]
Run Code Online (Sandbox Code Playgroud)

编辑:实际上,如果您只需要最新的,则可以使用has_one. 它适用于 Rails 4 和 Rails 3,只需稍微修改语法:

class Stations
  has_one :recent_measure, -> { order('created_at DESC')  }, class_name: 'Measure' # Rails 4
  has_one :recent_measure, order: 'created_at DESC', class_name: 'Measure' # Rails 3
end
Run Code Online (Sandbox Code Playgroud)

  • [此处](http://mrbrdo.wordpress.com/2013/09/25/manually-preloading-associations-in-rails-using-custom-scopessql/) 描述了 Rails 4 和 Postgres 类似情况的技巧避免加载所有子记录。我的机器上没有 Postgres 我无法验证,但你可以看看。 (2认同)