简体   繁体   中英

Active Record Query for Distant Association

I have the following relationships between records: 在此处输入图片说明

Given a Project record I need a list of all the Countries associated with all the Resources associated with the Project . No country should appear more than once.

To do this ignoring obvious performance issues, I could add a method to Resource :

  def countries
    resources.flat_map{|resource| resource.countries}.uniq
  end

My question is two-fold.

Is there a way of achieving this with a query in a performant way? And if not, how should I handle this situation?

[Update]

@MarekLipka's suggestion is:

resources.includes(:countries).map(&:countries).flatten.uniq

However this results in 60 hits, totalling 0.4 Seconds for 20 Projects:

Resource Load (1.2ms) SELECT "resources".* FROM "resources" WHERE "resources"."project_id" = 20 ORDER BY name

ResourceLocation Load (1.0ms) SELECT "resource_locations".* FROM "resource_locations" WHERE "resource_locations"."resource_id" IN (97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126)

Country Load (0.4ms) SELECT "countries".* FROM "countries" WHERE "countries"."id" IN (19, 31, 64, 82, 197, 169, 1, 161, 167)

[Update]

My latest attempt comes in about twice as fast as the above solution through using joins rather than includes , making 1 hit per resource in a total of ~0.2 seconds:

Country.joins(resource_locations: {resource: :project}).where(resources: {project_id: self}).uniq

This should be ok:

resources.includes(:countries).map(&:countries).flatten.uniq

includes method resolves the problem of N+1 queries by pre-loading appropriate associations.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM