简体   繁体   English

Rails 3根据关联计数进行查询

[英]Rails 3 query on condition of an association's count

In Rails 3 with mysql, suppose I have two models, Customers and Purchases, obviously purchase belongs_to customer.在带有 mysql 的 Rails 3 中,假设我有两个模型,客户和购买,显然购买属于客户。 I want to find all the customers with 2 orders or more.我想找到所有有 2 个或更多订单的客户。 I can simply say:我可以简单地说:

Customer.includes(:purchases).all.select{|c| c.purchases.count > 2}

Effectively though, the line above makes query on the magnitude of Customer.all and Purchase.all, then does the "select" type processing in ruby.但实际上,上面的行对 Customer.all 和 Purchase.all 的大小进行了查询,然后在 ruby 中进行了“选择”类型的处理。 In a large database, I would much prefer to avoid doing all this "select" calculation in ruby, and have mysql do the processing and only give me the list of qualified customers.在大型数据库中,我更愿意避免在 ruby 中进行所有这些“选择”计算,并让 mysql 进行处理,只给我合格客户的列表。 That is both much faster (since mysql is more tuned to do this) and significantly reduces bandwidth from the database.这既快得多(因为 mysql 更适合执行此操作)并显着减少了数据库的带宽。

Unfortunately I am unable to conjure up the code with the building blocks in rails(where, having, group, etc) to make this happen, something on the lines of (psudo-code):不幸的是,我无法用 rails 中的构建块(在哪里,拥有,组等)来制作代码来实现这一点,类似于(psudo-code):

Customer.joins(:purchases).where("count(purchases) > 2").all

I will settle for straight MySql solution, though I much prefer to figure this out in the elegant framework of rails.我将满足于直接的 MySql 解决方案,尽管我更喜欢在优雅的 rails 框架中解决这个问题。

No need to install a gem to get this to work (though metawhere is cool)无需安装 gem 即可使其正常工作(尽管 metawhere 很酷)

Customer.joins(:purchases).group("customers.id").having("count(purchases.id) > ?",0)

The documentation on this stuff is fairly sparse at this point.在这一点上,关于这些东西的文档相当稀少。 I'd look into using Metawhere if you'll be doing any more queries that are similar to this.如果您要进行更多与此类似的查询,我会考虑使用Metawhere Using Metawhere, you can do this (or something similar, not sure if the syntax is exactly correct):使用 Metawhere,您可以执行此操作(或类似的操作,不确定语法是否完全正确):

Customer.includes(:purchases).where(:purchases => {:count.gte => 2})

The beauty of this is that MetaWhere still uses ActiveRecord and arel to perform the query, so it works with the 'new' rails 3 way of doing queries.这样做的美妙之处在于 MetaWhere 仍然使用 ActiveRecord 和 arel 来执行查询,因此它适用于“新”rails 3 查询方式。

Additionally, you probably don't want to call .all on the end as this will cause the query to ping the database.此外,您可能不想在最后调用.all ,因为这会导致查询 ping 数据库。 Instead, you want to use lazy loading and not hit the db until you actually require the data (in the view, or some other method that is processing actual data.)相反,您希望使用延迟加载,并且在您实际需要数据(在视图中或处理实际数据的其他方法中)之前不访问数据库。

This is a bit more verbose, but if you want Customers where count = 0 or a more flexible sql, you would do a LEFT JOIN这有点冗长,但是如果您想要where count = 0的客户或更灵活的 sql,您可以执行LEFT JOIN

Customer.joins('LEFT JOIN purchases on purchases.customer_id = customers.id').group('customers.id').having('count(purchases.id) = 0').length

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM