如何在rails应用程序的ruby中使用postgresql“内部联接”?

时间:2014-11-15 00:31:17

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

我有一个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

2 个答案:

答案 0 :(得分:2)

由于您的模型声明了EventSensorIpHdr之间的关联,因此您只需撰写:

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

如果您要访问上述查询返回的每个sensors的相关ip_hdrsevents,则应添加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

答案 1 :(得分:1)

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

这里的问题更多的是纯代码问题。您提到的错误意味着符号 :event引用的对象没有为其定义sid方法,因此当你试图调用它时会引发NoMethodError

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

此外, Ruby 代码中join的{​​{1}}条件与您提供的SQL中的条件不同。还有一个引用的额外表tcphdr,它不在SQL中。