【问题标题】:How to execute complex Arel query in Rails 3 from Model如何从模型在 Rails 3 中执行复杂的 Arel 查询
【发布时间】:2010-08-08 03:46:09
【问题描述】:

我在 Rails 3 上,我有一个 SQL 查询,它由我在 Arel 中建立的几个连接组成。我想从我的一个模型中的方法运行此查询,但我不确定如何执行此操作。 arel 对象原来是 Arel::InnerJoin 类型,我想检索从该查询返回的所有对象的数组。我是否运行 ModelName.find_by_sql(my_arel_query_object) 来做到这一点?还是我运行 my_arel_query_object.each {...} 并遍历每个元组以手动将它们弹出到数组中?

我希望我说清楚了。任何见解将不胜感激。谢谢。

更新:这是我在用户模型中使用的代码:

def get_all_ingredients
    restaurants = Table(:restaurants)
    meals = Table(:meals)
    ingredients = Table(:ingredients)

    restaurants_for_user = restaurants.where(restaurants[:user_id].eq(self.id))
    meals_for_user = restaurants_for_user.join(meals).on(restaurants[:id].eq(meals[:restaurant_id]))  
    ingredients_for_user = meals_for_user.join(ingredients).on(meals[:id].eq(ingredients[:meal_id])) 

    return Ingredient.find_by_sql(ingredients_for_user.to_sql)
end

我在这里要做的是获取用户拥有的每家餐厅提供的所有餐点中使用的所有成分。成分_for_user 变量代表我希望运行的 Arel 查询。我只是不确定如何运行和返回所有成分,而且 Ingredient.find_by_sql... 似乎不正确。

结束

【问题讨论】:

  • 请显示您当前生成查询所需的代码。
  • @pushmatrix 你怎么解决这个问题?

标签: ruby-on-rails ruby database arel


【解决方案1】:

我不明白你为什么不做以下事情。 . .

Ingredient.joins({:meals=>:restaurants}).
           where(["restaurants.user_id = ?",self.id])

【讨论】:

  • 因为这种方式不能保证在复杂查询中使用索引。
  • 索引与 arel 无关 - 除了生成基于字符串的 sql 语句之外,rails 不与查询计划器交互。
  • 索引与性能息息相关。获得 10 毫秒与 800 毫秒的查询时间很重要。你必须关心这一点。 IE。在 PostgreSQL 案例中,在 ON 语句中注入过滤器将优化过滤 before 连接的查询。在我的情况下,显着减少了数据集的大小。将其放入 WHERE 将在逻辑上没有索引的巨大结果数据集上运行过滤器。所以是的,rails 确实与规划器交互。它提交查询。
  • 我的观点是,OP 可以通过不使用显式 arel 表来简化语法 - 我同意索引和查询很重要,当然您也同意使用显式 arel 表不是获得的唯一方法一个有效的查询。我想我们一直在谈论对方。
  • arel 不控制 sql 查询规划器,它只是一个生成 sql 语句的接口。对于任何具有显式 arel 表的查询,有一种方法可以在没有显式 arel 表的情况下构造它。
【解决方案2】:

Arel 对象(或更具体地说,Arel::Relation 对象)表示关系代数中的查询。查询在您第一次尝试访问其元素时执行,它像以前一样充当结果集。

例如,如果您有类似的查询

users.join(:photos).on(users[:id].eq(photos[:user_id]))

您可以在视图中迭代照片:

<% users.each do |user| %>
  <% users.photos.each do |photo| %>
    <%= photo.name %>
  <% end %>
<% end %>

示例取自Arel's README,可能有助于您更好地理解。

【讨论】:

  • 您的第一个代码示例中有一个小错字;照片上不应该有冒号。另外,我不确定您在第二个示例中在做什么。 “用户”和“照片”都是 Arel::Table 类型吗?
  • undefined method each' for #<:selectmanager>
【解决方案3】:

返回对象的方法(如您的get_all_ingredients 方法)应该是类方法。如何在 Ruby 中做到这一点并不是 100% 显而易见的,但一种方法是在声明方法时使用 self. 前缀。 (当您深入研究 Ruby 主义者通常所说的 eigenclass 时,这个 self. 最终是有意义的,但现在我们可以知道它是如何完成的)。

这是您的方法在成分模型中的样子:

def self.get_all_ingredients
    # insert your code from your question here
end

然后在您的视图中调用您的方法,例如:

&lt;%- Ingredients.get_all_ingredients.each do |current_ingredient| %&gt;
# do your things here
&lt;% end %&gt;

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-05-24
    • 2021-11-27
    • 1970-01-01
    相关资源
    最近更新 更多