我有一个名为Listing的模型:
class Listing < ActiveRecord::Base
belongs_to :user
end
我想检索100个列表以及每个列表的用户作为列表哈希中的子哈希,所有这些都使用ActiveRecord进行单个SQL调用。这就是我现在直接使用PostgreSQL的方式:
def listings
listings = ActiveRecord::Base.connection.execute("select row_to_json(t) as listing from (select *, row_to_json(users) as user from listings INNER JOIN users ON listings.user_id = users.id LIMIT 100) t")
render json: {listings:listings,listing_count:Listing.count}
end
没有循环列表来检索他们的用户,这非常耗时。 谢谢!
修改
我按照建议尝试了这个,但它没有返回用户:
2.2.1 :012 > Listing.joins(:user).limit(1)
Listing Load (0.6ms) SELECT "listings".* FROM "listings" INNER JOIN "users" ON "users"."id" = "listings"."user_id" LIMIT 1
=> #<ActiveRecord::Relation [#<Listing id: 1, user_id: 1, deleted: false, rent: "$950", deposit: "$950", availability: "6/18/2015", min_duration: "11", male_count: "0", female_count: "1", longitude: "-73.9767700960917", latitude: "40.75831025967895", location: "Midtown Center", comments: "Sequi acidus utor sublime cito autus suasoria. Ips...", photos: "1.jpg, 2.jpg, 3.jpg", cat: false, dog: false, doorman: true, large_room: true, apartment: true, house: false, garden: true, personal_bathroom: false, dog_friendly: true, cat_friendly: false, laundry: false, gym: true, elevator: true, renovated: true, furnished: false, smoking: true, smoke_free: false, air_conditioning: false, utilities_included: true, four_twenty_friendly: false, gay_friendly: false, vegan_friendly: false, vegetarian: true, kosher: false, girls_only: false, guys_only: true, created_at: "2015-07-17 20:09:21", updated_at: "2015-07-17 20:09:21">]>
答案 0 :(得分:1)
为什么单个SQL调用?我们避免N + 1加载是否足够?
时间复杂度几乎相同(O表示常数):
单个SQL调用:1 * O(n) 两个SQL调用:2 * O(n)
这里,O只是一个不同的常数。就可接受的运行时复杂性而言,因为它仍然是O(n)。
以此为前提:
听起来你想做的是预加载用户关联。 你可以这样做:
class Listing < ActiveRecord::Base
belongs_to :user
def self.to_hash_with_user
relation = includes(:user)
relation.map{ |record|
hash = record.as_json
hash['user'] = record.user.as_json
hash
}
end
end
现在你可以这样使用它了
# Get some relation, e.g. Listing.limit(100)
# Because of lazy loading, this will not do a db call yet
listings = Listing.limit(100)
render json: listings.to_hash_with_user.to_json
有关预加载记录的更多信息:http://blog.arkency.com/2013/12/rails4-preloading/
如果你想清理你返回的JSON,并且有更好的结构和灵活性,我强烈推荐这个宝石:https://github.com/rails-api/active_model_serializers
答案 1 :(得分:0)
左外连接应该这样做。它不会将其作为subhash返回,而是在响应中获得100个哈希值,每个哈希值包含所有用户和所有列表信息。
有关如何在rails 4中执行左外连接的信息 LEFT OUTER JOIN in Rails 4
所以在你的情况下
Listing.joins('LEFT OUTER JOIN users ON listing.user_id = users.id limit 100')
再次不是100%你正在寻找但它确实在一个查询中获得所有信息。