【问题标题】:Update more record in one query with Active Record in Rails使用 Rails 中的 Active Record 在一个查询中更新更多记录
【发布时间】:2013-08-30 15:59:07
【问题描述】:

有没有更好的方法在 Ruby on Rails 中用不同的值在一个查询中更新更多记录?我在 SQL 中使用 CASE 解决了这个问题,但是有什么 Active Record 解决方案吗?

基本上,当新列表从 jquery ajax 帖子返回时,我会保存新的排序顺序。

#List of product ids in sorted order. Get from jqueryui sortable plugin.
#product_ids = [3,1,2,4,7,6,5]

# Simple solution which generate a loads of queries. Working but slow.
#product_ids.each_with_index do |id, index|
#  Product.where(id: id).update_all(sort_order: index+1)
#end

##CASE syntax example:
##Product.where(id: product_ids).update_all("sort_order = CASE id WHEN 539 THEN 1 WHEN 540 THEN 2 WHEN 542 THEN 3 END")

case_string = "sort_order = CASE id "      

product_ids.each_with_index do |id, index|
  case_string += "WHEN #{id} THEN #{index+1} "
end

case_string += "END"

Product.where(id: product_ids).update_all(case_string)

这个解决方案运行速度很快,而且只有一个查询,但我创建了一个查询字符串,就像在 php.ini 中一样。 :) 你有什么建议?

【问题讨论】:

  • 你的表有多大,你真的想要一个查询吗?我认为要么您选择更易于阅读,并且有多个查询,要么您有一个查询并且它变得更加混乱。根据这个查询的执行频率(以及索引的设置方式),我认为多个查询应该没问题。
  • 罗吉尔,感谢您的评论。你说的对。我同意你的看法。如果我有一个包含 20 个元素的列表,包含 20 个查询,则需要 100-150 毫秒,所以没什么大不了的。但是一个查询只需要 2 毫秒,我得到了相同的结果。当然,在这种情况下,可能并不真正需要它,但如果了解一个用更少查询使数据库更快的一般概念,那就太好了。 :)
  • 我对您的方法是否正确,如果您更改两种产品的顺序,则需要更改表中每个产品(即行)的排序顺序(或至少每行之间' 2 个产品),因此随着产品表的增长,行更新的数量也会增长?在这种情况下,为什么不考虑一个简单地保存以逗号分隔的排序 id 字符串的新表呢?在展示产品之前阅读它,在重新订购后更新它?

标签: sql ruby-on-rails ruby-on-rails-4 arel


【解决方案1】:

您应该查看acts_as_list gem。它可以完成您需要的一切,并在幕后使用 1-3 个查询。它与 jquery 可排序插件完美匹配。它依赖于直接在 SQL 中递增/递减位置 (sort_order) 字段。

如果您的 UI/UX 依赖于用户手动保存订单(用户整理好物品然后点击更新/保存),这对您来说不是一个好的解决方案。但是,我强烈反对这种接口,除非有特定原因(例如,数据库中不能在新旧订单之间有中间状态,因为其他东西取决于该订单)。

如果不是这样,那么无论如何,只要在用户移动一个元素后进行异步更新(acts_as_list 将很好地帮助您实现这一点)。

退房:

https://github.com/swanandp/acts_as_list/blob/master/lib/acts_as_list/active_record/acts/list.rb#L324

# This has the effect of moving all the higher items down one.
def increment_positions_on_higher_items
  return unless in_list?
  acts_as_list_class.unscoped.where(
    "#{scope_condition} AND #{position_column} < #{send(position_column).to_i}"
  ).update_all(
    "#{position_column} = (#{position_column} + 1)"
  )
end

【讨论】:

  • 谢谢。看起来很有希望。我一定试一试。
猜你喜欢
  • 1970-01-01
  • 2021-11-26
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-07-14
  • 1970-01-01
  • 2013-12-13
相关资源
最近更新 更多