Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/mysql/62.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Mysql 更新元素后获取查询集计数的最佳方法_Mysql_Ruby On Rails_Ruby - Fatal编程技术网

Mysql 更新元素后获取查询集计数的最佳方法

Mysql 更新元素后获取查询集计数的最佳方法,mysql,ruby-on-rails,ruby,Mysql,Ruby On Rails,Ruby,我正在寻找在rails中获取查询集大小的最佳方法。但是,元素是在循环中更新的,我需要更新之前的元素计数。这里是一些例子马车!代码 p = participations.where(invited_at: nil).limit(50) p.each do |participation| # Invite may raise an exception, but also contains operations that # cannot be undone participatio

我正在寻找在rails中获取查询集大小的最佳方法。但是,元素是在循环中更新的,我需要更新之前的元素计数。这里是一些例子马车!代码

p = participations.where(invited_at: nil).limit(50)
p.each do |participation|
   # Invite may raise an exception, but also contains operations that
   # cannot be undone
   participation.invite()
   participation.invited_at = Time.zone.now
   participation.save
end

DoStuff() if p.count > 0

此代码不起作用,因为P.CULL中的调用创建了一个新的数据库查询,该查询不考虑在循环中已更新的记录。因此,如果记录少于50条,则所有记录都会更新,并且不会调用DoStuff

rails中最惯用的处理方法是什么:

将if p.count部分移出循环,并且仅在有任何记录时才进入循环? 将p.count替换为p.size如果我正确理解大小,这不会导致任何额外的查询 计算循环中的迭代次数,然后使用该次数 我觉得1在ruby中是最地道的,但我在这门语言中没有太多经验

编辑:改进示例,使其更接近原始代码

编辑:


问题不在于对循环中的参与者执行的更新查询。这些查询应该是单独的查询,以跟踪哪些参与已被处理,即使出现错误也是如此。相反,问题在于,只要循环中有任何处理过的记录,就应该调用DoStuff。但是,由于count在处理记录后执行新查询,因此如果要处理的元素少于50个,则所有元素都将更新,并且不会调用DoStuff。

这就是count(始终执行查询)和size(如果加载对象,将返回加载对象的数量)之间的差异,否则,我们将退回计数。因此,最简单的修复方法是用大小替换计数

但是每个都返回它迭代的集合,因此如果p.each&block.any?如果有多行块,看起来就不好看了

一种更简洁的方法是将代码封装在方法中,并添加一个guard子句,这样一来,审阅者就不必知道大小和计数之间的差异,也不必检查每个元素是否产生了一个至少包含一个元素的集合

def process_invitations
  p = participations.where(invited_at: nil).limit(50)
  return if p.none?

  p.each do |participation|
   # Invite may raise an exception, but also contains operations that
   # cannot be undone
   participation.invite()
   participation.invited_at = Time.zone.now
   participation.save
  end

  DoStuff()
end
您甚至可以取消限制并使用p.first50.do

将if p.count部分移出循环,并且仅在有任何记录时才进入循环

。如果没有记录,则每个都不会进入循环。如果您想要验证,请尝试:

MyModel.none.each { puts "Hello world" }
如果你想要一种更惯用的方法,那么如果你关心结果,就不要使用每种方法。只有当您只关心迭代的副作用时,才应该使用每种方法

取而代之的是使用map或其他许多迭代方法中的一种

def process_invitations
  p = participations.where(invited_at: nil).limit(50)
  p.map do |participation|
   # Invite may raise an exception, but also contains operations that
   # cannot be undone
   participation.invite()
   participation.invited_at = Time.zone.now
   participation.save
  end.reject.yeild_self do |updates|
    # run do_stuff if any of the records where updated
    do_stuff() if updates.any?
  end
end
或者,如果您只想对更新的记录执行以下操作:

def process_invitations
  p = participations.where(invited_at: nil).limit(50)
  p.map do |participation|
   # Invite may raise an exception, but also contains operations that
   # cannot be undone
   participation.invite()
   participation.invited_at = Time.zone.now
   participation if participation.save
  end.reject.yeild_self do |updated|
    do_stuff(updated) if updated.any?
  end
end
def process_invitations
  p = participations.where(invited_at: nil).limit(50)
  p.map do |participation|
   # Invite may raise an exception, but also contains operations that
   # cannot be undone
   participation.invite()
   participation.invited_at = Time.zone.now
   participation if participation.save
  end.reject.map do |record|
    do_stuff(record)
  end
end
或者对更新的每个记录执行以下操作:

def process_invitations
  p = participations.where(invited_at: nil).limit(50)
  p.map do |participation|
   # Invite may raise an exception, but also contains operations that
   # cannot be undone
   participation.invite()
   participation.invited_at = Time.zone.now
   participation if participation.save
  end.reject.yeild_self do |updated|
    do_stuff(updated) if updated.any?
  end
end
def process_invitations
  p = participations.where(invited_at: nil).limit(50)
  p.map do |participation|
   # Invite may raise an exception, but also contains operations that
   # cannot be undone
   participation.invite()
   participation.invited_at = Time.zone.now
   participation if participation.save
  end.reject.map do |record|
    do_stuff(record)
  end
end
但是,由于count在处理记录后执行新查询,…,所以使用size,否?p已经在内存中,如果没有任何更改它的值,那么DoStuff的使用不应该受到影响。