Arel 聚合、计数、外连接?

发布于 2024-09-30 17:25:26 字数 227 浏览 5 评论 0原文

我有一个 Fact 模型,它 has_many :votes。投票还有一个 user_id 字段。 我想在 Fact 模型的范围内表达以下内容:给我所有 0 票且 user_id 等于 X 的事实。

我不太明白对 Arel 足够熟悉,了解我如何解决这个问题。有想法吗?

I have a Fact model, which has_many :votes. Votes also have a user_id field.
I'd like to express the following in a scope for the Fact model: Give me all Facts which have 0 votes with a user_id equal to X.

I'm not quite familiar enough with Arel to understand how I might tackle this. Ideas?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

野心澎湃 2024-10-07 17:25:26

这是有效的:

class Fact < ActiveRecord::Base
  scope :by_user, lambda { |id| joins(:user).where('users.id == ?', id).readonly(false)    }
  scope :vote_count, lambda { |count| where('? == (select count(fact_id) from votes where votes.fact_id == facts.id)', count)}
end

Fact.by_user(1).vote_count(0)

vote_count 范围有点sqlly,但您可以根据需要链接这些查找器,您还可以使用以下命令查看底层 sql:

Fact.by_user(1).vote_count(0).to_sql

并且根据您的评论,您可以通过首先声明关系在纯 Arel 中执行相同的操作:

f = Arel::Table.new(:facts)
v = Arel::Table.new(:votes)
u = Arel::Table.new(:users)

然后编写查询并将其呈现为 sql。

sql = f.join(u).on(f[:user_id].eq(1)).where('0 == (select count(fact_id) from votes where votes.fact_id == facts.id)').to_sql

您可以使用运算符对列进行操作: f[:user_id].eq(1)

然后使用它:

Fact.find_by_sql(sql)

我确信您还可以做更多的事情来获得更优雅的语法(没有 'where 0 == ...' )。另外,我很确定 Rails3 范围在幕后使用 Arel - http://m.onkey .org/active-record-query-interface

This works:

class Fact < ActiveRecord::Base
  scope :by_user, lambda { |id| joins(:user).where('users.id == ?', id).readonly(false)    }
  scope :vote_count, lambda { |count| where('? == (select count(fact_id) from votes where votes.fact_id == facts.id)', count)}
end

Fact.by_user(1).vote_count(0)

The vote_count scope is a bit sqly but you can chain these finders however you like, you can also see the underlying sql with:

Fact.by_user(1).vote_count(0).to_sql

And further to your comment, you might do the same in pure Arel by first declaring the Relations:

f = Arel::Table.new(:facts)
v = Arel::Table.new(:votes)
u = Arel::Table.new(:users)

Then composing the query and rendering it to sql.

sql = f.join(u).on(f[:user_id].eq(1)).where('0 == (select count(fact_id) from votes where votes.fact_id == facts.id)').to_sql

You can act on columns with operators: f[:user_id].eq(1)

Then using it:

Fact.find_by_sql(sql)

I'm sure theres a lot more that you could do to get a more elegant syntax (without the 'where 0 == ...' ). Also I'm pretty sure Rails3 scopes use Arel behind the scenes - http://m.onkey.org/active-record-query-interface

新一帅帅 2024-10-07 17:25:26

我最终解决了这个问题,范围如下:

  scope :not_voted_on_by_user, lambda {|user_id| select("distinct `facts`.*").joins("LEFT JOIN `votes` ON `facts`.id = `votes`.fact_id").where(["votes.user_id != ? OR votes.user_id IS NULL",user_id])}

I ended up solving this problem with the following scope:

  scope :not_voted_on_by_user, lambda {|user_id| select("distinct `facts`.*").joins("LEFT JOIN `votes` ON `facts`.id = `votes`.fact_id").where(["votes.user_id != ? OR votes.user_id IS NULL",user_id])}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文