Ruby on Rails 中“any?”和“exists?”之间的区别?

J3R*_*3RN 9 ruby activerecord ruby-on-rails ruby-on-rails-4

在 Ruby on Rails 中,似乎有两种方法可以检查集合中是否包含任何元素。

也就是说,它们是ActiveRecord::FinderMethods 的存在吗?ActiveRecord::Relation 有什么关系?. 在通用查询 (Foo.first.bars.exists?Foo.first.bars.any?) 中运行这些会生成等效的 SQL。有什么理由使用一个而不是另一个吗?

Jos*_*ody 12

#any并且#exists?是非常不同的野兽,但查询相似。

主要是#any?接受一个块——它用这个块检索关系中的记录,调用#to_a,调用块,然后用 命中它Enumerable#any?。没有块,它相当于!empty?并计算关系的记录。

#exists? 始终查询数据库,从不依赖预加载的记录,并将 LIMIT 设置为 1。与#any?. #exists?还接受一个选项参数作为应用条件,如您在文档中所见。


Seb*_*lma 7

的使用量ActiveRecord#any?减少超过ActiveRecord#exists?. 与任何?在传递块的情况下,您可以检查该数组中的某些元素是否符合条件。与 类似,Enumerable#any?但不要混淆它们。

通过将块已传递给它的情况下访问的关系转换为数组,并生成和访问块参数,以“手工制作”的方式实现“Ruby”方法,实现其定义的内部ActiveRecord#any?逻辑。Enumerable#any?any?

添加的方便的 else 旨在返回空的否定?应用于关系。这就是为什么您可以通过两种方式检查模型中是否有记录,例如:

User.count # 0
User.any?  # false
# SELECT  1 AS one FROM "users" LIMIT ?  [["LIMIT", 1]]
User.exists? # false
# SELECT  1 AS one FROM "users" LIMIT ?  [["LIMIT", 1]]
Run Code Online (Sandbox Code Playgroud)

您还可以检查“有吗?” 方式,如果某些记录属性具有特定值:

Foo.any? { |foo| foo.title == 'foo' } # SELECT "posts".* FROM "posts"
Run Code Online (Sandbox Code Playgroud)

或者通过使用exists来节省“效率”?并改进您的查询和代码行:

Foo.exists?(title: 'foo') # SELECT  1 AS one FROM "posts" WHERE "posts"."title" = ? LIMIT ?  [["title", "foo"], ["LIMIT", 1]]
Run Code Online (Sandbox Code Playgroud)

ActiveRecord#exists?提供了许多实现,并且旨在在 SQL 级别工作,而不是any?在 SQL 级别工作,如果您不传递块,无论如何都会将您在数组中使用的关系转换为关系。


小智 6

这里的答案都是基于非常过时的版本。此提交从 2016 / ActiveRecord 5.1 更改为在没有块传递时empty?调用,以在未预加载时调用。因此,在模糊现代的 Rails 中,当不传递任何块时,唯一的区别是一些额外的方法调用和否定,以及忽略预加载的结果。any?exists?