简体   繁体   English

Rails查找所有相关记录均符合条件的位置

[英]Rails find where ALL associated records meet condition

I'm trying to get all the clients that have doctors associated BUT none of them has started their first session (one client has_many doctors and can have first sessions with each of them). 我正在尝试让所有与医生相关联的客户,但他们都没有开始第一次会议(一个客户有很多医生,并且可以与每个人进行第一次会议)。

So far I have: 到目前为止,我有:

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

But this doesn't work when a client has for example 2 doctors. 但这在客户有两名医生的情况下不起作用。 the first doctor.first_session = null but the second one is not. 第一个doctor.first_session = null,但第二个不是。 This case will return the client and it don't want it to. 这种情况将返回客户端,并且它不希望这样做。

Any ideas? 有任何想法吗?

This is one of those cases where in order to find records that don't meet a certain condition, you do it by finding all records except those that meet the condition. 这是其中一种情况,其中为了查找不满足特定条件的记录,您可以通过查找除满足条件的记录之外的所有记录来做到这一点。 In SQL this is done with a subquery in the WHERE clause. 在SQL中,这是通过WHERE子句中的子查询完成的。

For cases like this, the squeel gem is extremely helpful, because it encapsulates the SQL complexity. 对于这种情况, squeel gem非常有用,因为它封装了SQL的复杂性。 This is how I would do it (with squeel): 这就是我会做的(使用squeel):

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

Note that you can do this without squeel, but you'll have to get your hands (and your code) dirty with SQL. 请注意,您可以在不费力的情况下执行此操作,但是您必须使SQL(使您的手(和代码)变得肮脏)。

This will work, but may be a little less efficient since it does some of the work in ruby instead of all in the db. 这会起作用,但效率可能会稍低一些,因为它在ruby中完成了部分工作,而不是在db中完成了所有工作。

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

Logically, that should fetch all the clients, and then in ruby, the select will evaluate the condition in the block and those clients that return true will be assigned to clients. 从逻辑上讲,应该获取所有客户端,然后在ruby中,select将评估块中的条件,并将那些返回true的客户端分配给客户端。

The condition block will return true only if all of that client's doctors have a nil first_session. 仅当该委托人的所有医生的null first_session为nil时,条件块才返回true。

Hope that helps. 希望能有所帮助。 There's probably a more efficient way to do this using subselects, but the syntax for that is likely to depend on which database you're using. 使用子选择执行此操作可能是一种更有效的方法,但是其语法可能取决于所使用的数据库。

Well, I found a solution that involved two queries. 好吧,我找到了一个涉及两个查询的解决方案。

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')

Thank you all! 谢谢你们!

You could create a method in your Client model which returns true if any first_session on a client's doctors is true, something like... 您可以在Client模型中创建一个方法,如果客户医生的first_session为true,则该方法返回true,例如...

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

This is pseudocode and may need to be tweaked first 这是伪代码,可能需要先进行调整

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM