使用PostgreSQL和Rails保留订单

时间:2017-07-07 17:31:01

标签: ruby-on-rails ruby postgresql rails-activerecord

我正在运行一些弹性搜索查询,然后将这些结果转换为Active Record。当然,订单不会保留。

我之前有过这项工作,但现在我正在使用Ruby 2.3.1Rails 5.1.1

我已经尝试了以下所有解决方案,所以我开始认为这是这个环境的一些错误。

def self.find_ordered(ids)
  order_clause = "CASE id "
  ids.each_with_index do |id, index|
    order_clause << sanitize_sql_array(["WHEN ? THEN ? ", id, index])
  end
  order_clause << sanitize_sql_array(["ELSE ? END", ids.length])
  where(id: ids).order(order_clause)
end

此外:

def self.order_by_ids(ids)
  order_by = ["case"]
  ids.each_with_index.map do |id, index|
    order_by << "WHEN id='#{id}' THEN #{index}"
  end
  order_by << "end"
  order(order_by.join(" "))
end

https://github.com/panorama-ed/order_as_specified gem:

Product.order_as_specified(id: [ids])

https://github.com/khiav223577/find_with_order

Product.find_with_order([ids])

所有这些都应该有效,但所有这些都在运行后默认回数字顺序。我在控制台中运行它们,因此无法运行代码。

编辑:控制台中的请求示例。

Product.where(id: [100,5,10]).order_by_ids([100,5,10]).pluck(:id)
  (127.0ms)  SELECT "products"."id" FROM "products" WHERE 
  "products"."id" IN (100, 5, 10) ORDER BY "products"."id" ASC, case 
 WHEN id='100' THEN 0 WHEN id='5' THEN 1 WHEN id='10' THEN 2 end
 => [5, 10, 100]

2 个答案:

答案 0 :(得分:0)

从日志中查看最终的SQL,我们看到了:

ORDER BY "products"."id" ASC, ...

这表明某个地方正在做的事情:

order(:id)

当您的查询中出现神秘信息时,通常的疑问是模型中的default_scope。我倾向于认为默认范围是邪恶的,当它们包含order电话时会加倍。

去寻找默认范围并摆脱它。如果你无法摆脱它(因为某些地方取决于它),那么在添加reorder('')之前,先将reorder(nil)order by case ...投入查询,然后在其周围进行克制填充或使用reorder('case ... end')一次性替换ORDER BY内容;像这样的东西:

def self.order_by_ids(ids)
  #... as before
  reorder(order_by.join(" "))
end

def self.order_by_ids(ids)
  #... as before
  reorder(nil).order(order_by.join(" "))
end

def self.order_by_ids(ids)
  #... as before
  reorder('').order(order_by.join(" "))
end

# etc.

您也可以使用unscope(:order),但unscope可以执行您不想要的事情,因此最好使用reorder,因为它完全符合您的要求,而不是其他任何内容。

答案 1 :(得分:-1)

保留订单的最简单方法是根据不变的字段进行排序。在Rails中,除非您不使用时间戳,否则created_at将是一个字段。