如何按Activerecord中的计算值排序?

qui*_*bit 2 activerecord ruby-on-rails rails-activerecord

我有一个rails API,它将JSON返回到我的React前端.我正在尝试按集合中每个项目的计算值进行排序.我有一个Space具有area属性和count属性的模型.我想作为排序依据的响应total_area这仅仅是area * count.我可以使用这个,sort_by但即使记录少于100个,这个过程也很慢:

@spaces = Space.all
@spaces = @spaces.sort_by(&:total_area) 
Run Code Online (Sandbox Code Playgroud)

哪里total_area是一个Space类的方法:

def total_area
  self.area * self.count
end
Run Code Online (Sandbox Code Playgroud)

无论如何,在数据库中这样做是为了提高速度吗?我尝试过使用这个order方法:

@spaces.order( "count * area" => :asc)
Run Code Online (Sandbox Code Playgroud)

但我得到以下postgres错误:

PG::UndefinedColumn: ERROR:  column spaces.count * area does not exist
Run Code Online (Sandbox Code Playgroud)

可以在数据库中执行此操作吗?任何有关我如何能够提出的建议,或者我如何更快地做到这一点都将非常感激.

mu *_*ort 6

当您提交#order哈希时:

@spaces.order("count * area" => :asc)
Run Code Online (Sandbox Code Playgroud)

它假定键是列名,因此它将这样的SQL发送到数据库:

order by "count * area" asc
Run Code Online (Sandbox Code Playgroud)

因此PG::UndefinedColumn例外.顺便说一句,在SQL中使用双引号来引用列和表名等标识符.

如果要将表达式作为ORDER BY子句的一部分发送到数据库,则需要将该表达式#order作为字符串传递:

@spaces.order('count * area')
# If you want to be explicit about the sorting direction:
@spaces.order('count * area asc')
# If you might have other tables with those column names:
@spaces.order('spaces.count * spaces.area')
Run Code Online (Sandbox Code Playgroud)

请注意,较新版本的Rails会抱怨:

DEPRECATION WARNING:使用非属性参数调用的危险查询方法(其参数用作原始SQL的方法)

当你尝试传递一个字符串,#order但你可以通过添加一个Arel.sql调用来解决这个问题:

@spaces.order(Arel.sql('count * area'))
@spaces.order(Arel.sql('count * area asc'))
@spaces.order(Arel.sql('spaces.count * spaces.area'))
Run Code Online (Sandbox Code Playgroud)