我有一个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
答案 0 :(得分:2)
由于您的模型声明了Event
与Sensor
和IpHdr
之间的关联,因此您只需撰写:
Event.
joins(:sensors, :ip_hdrs).
where("timestamp >= ?", @ts).
order("event.timestamp desc").
uniq
如果您要访问上述查询返回的每个sensors
的相关ip_hdrs
和events
,则应添加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中。