ruby-on-rails 轨道3 -选择并包含?

1bqhqjot  于 2022-11-26  发布在  Ruby
关注(0)|答案(5)|浏览(186)

下面是一个包含的嵌套select:

@items = Item.where("complete = ?", true).includes( :manufacturer, {:order=>[:supplier, :agent] })

这是一个繁重的查询,因为它从上面包含的所有表中提取了数千行数据。
如何使查询只选择特定字段?

  • user.name,用户.创建时间
  • 订单创建时间
  • supplier.name
  • agent.name
  • manufacturer.name
pepwfjgg

pepwfjgg1#

ARel中有一个select方法,但是您必须使用正确的表名(即复数,如果您有多态模型或者如果您正在使用set_table_name或其他类似的非标准实践,请注意)

@items = Item.
  select('users.name', 'users.created_at', 'orders.created_at', 'suppliers.name', 'agents.name', 'manufacturers.name').
  where(:users => { :fulfilled => true }).
  includes(:orders => [:supplier, :agent], :manufacturer)

“我们可以使用不包含连接的选择”- @Bhavesh_A_P

注:

正如上面@Bhavesh_A_P指出的,selectincludes不会产生一致的行为。看起来如果包含的关联没有返回结果,select将正常工作,如果它返回结果,select语句将不起作用。事实上,它将被完全忽略。这样您的select语句就可以引用无效的表名,并且不会产生错误。selectjoins将产生一致的行为。

rjjhvcjd

rjjhvcjd2#

实际上,我们不能使用select和includes,它只能和joins一起使用。

tmb3ates

tmb3ates3#

在链接中包含'select'方法的呼叫并不能解决问题。在我们建置的类似ActiveRecord::Relation中,呼叫'includes'似乎会覆写任何'select'的呼叫。

scope :active, where("hired_on < ? AND (separated_on > ? OR separated_on IS NULL)", Time.now, Time.now )

scope :with_role, lambda {|roles| includes(:team_member_roles).where(:team_member_roles => {:role => roles } ) }

scope :with_site_code, lambda {|site_codes| includes(:team_member_sites).where(:team_member_sites => {:site_code => site_codes } ) }

TeamMember.select("team_members.email, team_members.first_name, team_members.last_name").active.with_site_code(params[:site_code]).with_role(["senior_editing", "senior_and_reg_editing"])

如图所示,查询会选取所有数据行。
当这两个范围使用'joins'而不是'includes'时,查询会运作:仅选择3个指定的列。

iyr7buue

iyr7buue4#

Item.where("fulfilled = ?", true)
    .includes({:orders =>[:suppliers, :agents]}, :manufacturers)
    .select("users.name, users.created_at, orders.created_at, suppliers.name, agents.name").
    .order('orders.created_at DESC')
8fq7wneg

8fq7wneg5#

正如其他人所指出的,如果有.includes(...),使用.select(...)会被覆盖。我不喜欢这样...所以我找到了一个补丁来使它工作,并将其作为**The Brick的一部分发布。
通过像这样覆盖ActiveRecord::Associations::JoinDependency.apply_column_aliases()
*,当您添加.select(...)时,它可以作为筛选器来选择构建哪些列别名。
加载了gem 'brick'之后,为了启用这种选择性行为,添加特殊列名:_brick_eager_load作为.select(...)中的第一个条目,这将在构建别名时启用列过滤。

Employee.includes(orders: :order_details)
        .references(orders: :order_details)
        .select(:_brick_eager_load,
                'employees.first_name', 'orders.order_date', 'order_details.product_id')

由于外键对于正确关联所有内容是必不可少得,因此它们是自动添加得,因此您不需要将它们包括在选择列表中.
希望它可以保存您的查询时间和一些内存!

相关问题