Rails查找所有关联记录满足条件的位置

时间:2013-12-23 17:47:26

标签: ruby-on-rails activerecord

我正在努力让所有拥有医生的客户联系起来,但他们都没有开始他们的第一次会议(一个客户有很多医生,可以与他们各自进行第一次会议)。

到目前为止,我有:

@clients =  Client.joins(:doctors).where('doctors.first_session IS NULL').order('clients.id DESC')

但是,当客户有例如2名医生时,这不起作用。第一个doctor.first_session = null但第二个不是。这种情况将返回客户端,它不希望它。

有什么想法吗?

4 个答案:

答案 0 :(得分:2)

这是为了查找不符合特定条件的记录的情况之一,您可以通过查找除满足条件的记录之外的所有记录来执行此操作。在SQL中,这是通过WHERE子句中的子查询完成的。

对于这样的情况,squeel gem非常有用,因为它封装了SQL的复杂性。我就是这样做的(带有吱吱声):

scope :visited_doctor, joins(:doctors).where { doctors.first_visit != nil }
scope :not_visited_doctor, where { id.not_in(Patient.visited_doctor.select(:id)) }

请注意,您可以在没有发出吱吱声的情况下执行此操作,但是您必须使用SQL弄脏您的手(和您的代码)。

答案 1 :(得分:0)

这可行,但可能效率稍低,因为它在ruby中完成了一些工作,而不是db中的所有工作。

clients = Client.order('clients.id DESC').include(:doctors).select do |client|
  client.doctors.all? {|doctor| doctor.first_session.nil? }
end

逻辑上,这应该获取所有客户端,然后在ruby中,select将评估块中的条件,并且那些返回true的客户端将被分配给客户端。

只有当该客户的所有医生都有nil first_session时,条件块才会返回true。

希望有所帮助。使用子选择可能有一种更有效的方法,但其语法可能取决于您正在使用的数据库。

答案 2 :(得分:0)

好吧,我找到了一个涉及两个查询的解决方案。

avoid_ids_results = Doctors.select('client_id')
                        .where("first_session IS NOT NULL")
                        .map(&:client_id).join(', ')

@clients =  Clients.
              joins(:doctors).
              where('clients.id NOT IN (' + avoid_ids_results + ')').
              order('clients.id DESC')

谢谢大家!

答案 3 :(得分:-4)

您可以在Client模型中创建一个方法,如果客户端医生的first_session为真,则返回true,如...

def has_first?
  self.doctors.each do |doctor|
    return true if !doctor.first_session.nil?
  end
  return false
end

这是伪代码,可能需要先调整