【问题标题】:How can I use postgresql "inner join" in a ruby on rails app?如何在 ruby​​ on rails 应用程序中使用 postgresql“内部连接”?
【发布时间】:2014-11-15 00:31:17
【问题描述】:

我有一个 PostgreSQL 查询,我正在我的 rails 应用程序中查找。

SQL 查询是:

SELECT *
       FROM event
       INNER  JOIN sensor ON (sensor.sid = event.sid)
       INNER  JOIN iphdr ON (iphdr.cid = event.cid) AND (iphdr.sid = event.sid);

此查询在 PostgreSQL 中运行良好。我希望它可以帮助我在我的 rails 应用程序中实现更少的 N+1 查找,但我没有成功实现它。

这是我的尝试:

ips_events = Event.joins(:sensor).on(:sensor.sid = :event.sid).joins(:ip_hdr).on(:ip_hdr.cid = :event.cid && :ip_hdr.sid = :event.sid).all.(conditions: ['timestamp >= ?', @ts]).reverse.uniq

我收到“NoMethodError: undefined method `sid' for :event:Symbol”

这是传感器模型:

class Sensor < ActiveRecord::Base
  # DB Schema
  # sid | hostname | interface | filter | detail | encoding | last_cid
  #--------------------------------------------------------------------

  attr_accessible :sid, :hostname, :interface, :filter, :detail, :encoding, :last_cid
  self.table_name = 'sensor'

  belongs_to :event,
             :foreign_key => :sid

end

事件模型:

class Event < ActiveRecord::Base
  # DB Schema
  # sid | cid | signature | timestamp
  #----------------------------------

  attr_accessible :sid, :cid, :signature, :timestamp
  self.primary_keys = :sid, :cid
  self.table_name = 'event'
  has_many :sensors,
           :foreign_key => :sid
  has_many :signatures,
           :foreign_key => :sig_id,
           :primary_key => :signature
  has_many :ip_hdrs,
           :foreign_key => [:sid, :cid]
  has_many :tcp_hdrs,
           :foreign_key => [:sid, :cid]
  has_many :udp_hdrs,
           :foreign_key => [:sid, :cid]
end

这是 ip_hdr 模型:

class IpHdr < ActiveRecord::Base
  # DB Schema
  # sid | cid | ip_src | ip_dst | ip_ver | ip_tos | ip_len | ip_id | ip_flags | ip_off | ip_ttl | ip_proto | ip_csum
  #-----------------------------------------------------------------------------------------------------------------

  attr_accessible :sid, :cid, :ip_src, :ip_dst, :ip_ver, :ip_tos, :ip_len, :ip_id, :ip_flags, :ip_off,
                  :ip_ttl, :ip_proto, :ip_csum
  self.primary_keys = :sid, :cid
  self.table_name = 'iphdr'
  belongs_to :event,
             :foreign_key => [:sid, :cid]
end

【问题讨论】:

  • 您正在调用 Symbol 对象上的方法,就好像它们是您的 ActiveRecord 模型的实例一样。请参阅guides.rubyonrails.org/… 了解更多信息。您需要发布要加入的模型的源代码,以确保为 join 方法定义了正确的关系才能正常工作。

标签: ruby-on-rails ruby ruby-on-rails-3 postgresql


【解决方案1】:

由于您的模型声明了 EventSensorIpHdr 之间的关联,因此您可以简单地编写:

Event.
  joins(:sensors, :ip_hdrs).
  where("timestamp >= ?", @ts).
  order("event.timestamp desc").
  uniq

如果您要为上述查询返回的每个events 访问关联的sensorsip_hdrs,您应该像这样添加includes

Event.
  joins(:sensors, :ip_hdrs).
  where("timestamp >= ?", @ts).
  order("event.timestamp desc").
  uniq.
  includes(:sensors, :ip_hdrs)

添加 includes 是 ActiveRecord 加载关联模型的提示。所以上面会发生在三个查询中:一个加载事件,一个加载传感器,一个加载 ip_hdrs。请参阅Active Record Guide 了解更多信息。

【讨论】:

  • 感谢您的帮助,现在不抛出错误,但不是我真正想要的。我需要像在 SQL 中使用的那样使用主键。(sensor.sid = event.sid) 和 (iphdr.cid = event.cid) AND (iphdr.sid = event.sid)。
  • 你让我走向了正确的方向,这就是我正在使用的。ips_events = Event.includes(:ip_hdrs,:tcp_hdrs,:udp_hdrs,:signatures).all(conditions: ['timestamp &gt;= ?', @ts]).reverse.uniq
  • 酷!使用all(conditions) 有点奇怪——我怀疑您应该能够使用上面的where 子句。此外,根据返回的行数,使用 SQL order 子句而不是 reverse 可能会获得更好的性能,因为前者将由数据库管理,而后者将在 Ruby 中发生。但我可以理解,如果它按原样工作,我不想惹它!
  • 我希望减少 ruby​​ 并获得更好的性能,谢谢!我试试看。
  • 祝你好运。哦!还有一件事:你不需要uniq,除非你使用joins,因为joins 的使用会引入重复event 模型的可能性。
【解决方案2】:

这不是 RailsPostgres 本身的问题。 joins 是用于 inner join 的正确方法(这是 Postgres 中的默认 join)。

这里的问题更多是纯代码问题。您提到的错误意味着 symbol :event 引用的 object 没有为它定义 sid 方法,因此 NoMethodError当您尝试调用它时引发。

没有:event 后面的 的代码,我只能推测,但很可能您需要将sid 作为另一个字段添加到您的数据模型 ,然后应该使该方法可用(假设您正在使用,比如说,ActiveRecord,这似乎很可能,基于上面使用的代码语法)。

此外,您的 Ruby 代码中 tcphdrjoin 条件与您提供的 SQL 中的条件不同。还有一个额外的表,udphdr,被引用,它不在 SQL 中。

【讨论】:

  • 这是不正确的。发生错误是因为编写的代码尝试在:event symbol 上调用sid 方法。此上下文中的符号不​​代表 ActiveRecord 模型——它只是一个符号,因此将 sid 添加到数据模型中不会解决问题。 @Greg 在上面附加到问题的评论中是正确的。
猜你喜欢
  • 2014-02-12
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-08-09
  • 2010-10-22
  • 2015-09-20
  • 2016-11-04
相关资源
最近更新 更多