Ruby 在 Rails 上:带排序的左外连接
Ruby on Rails: Left Outer Join with Sort
我有一个用于发送电子邮件的 RoR 应用程序,我有联系人、收件人和用户模型,其中一个用户可以有多个联系人,一个联系人可以有多个收件人。数据如下所示:
User
ID Name
1 Ben
2 Emily
3 Brian
Contact
ID Name User_ID
1 Jack 1
2 Joe 2
3 Chloe 2
4 Jacob 1
5 Trevor 3
Recipient
ID Contact_ID Email_ID (not relevant for this question)
1 1 2
2 1 1
3 4 5
4 1 6
5 2 8
我想做的是在联系人的索引页上,显示属于一个用户的所有联系人,允许用户选择按什么排序,比如姓名和收到的电子邮件数量。
我遇到的问题是我可以毫无问题地显示属于一个用户的所有联系人,但我很难让用户根据他们收到的电子邮件数量对联系人进行排序。他们收到的电子邮件数量可以通过计算具有相同联系人 ID 的收件人数量来计算。我有这个问题的原因是因为我想显示属于用户的所有联系人,无论他们是否收到电子邮件(联系人可能收到 0 封电子邮件)。我试过的代码是:
@contacts = Contact.where(user_id: session[:user_id]).all.order(params.fetch(:sort, 'id asc'))
但这不允许用户按联系人收到的电子邮件数量进行排序。
我也试过这个:
@contacts = Contact.where(user_id: session[:user_id]).joins(:recipients).group('contacts.id').all.order(params.fetch(:sort, 'id asc'))
但这只显示已收到电子邮件的联系人。
我也试过这个:
@contacts = Contact.where(user_id: session[:user_id]).joins("LEFT OUTER JOIN contacts ON contacts.id = recipients.contact_id").all.order('max(recipients.contact_id) DESC')
这会显示所有已收到和未收到电子邮件的联系人并允许排序,但会显示重复数据。 IE。使用以上数据,如果 Ben 查看他的联系人 (user_id 1),他可以看到 Jack 和 Jacob,但是因为 Jack 收到了 3 封电子邮件,他会看到以下内容:
First Name:
Jack
Jacob
Jack
Jack
Jack
有办法解决吗?请注意,我目前在 index.html.erb
上使用以下代码以允许用户 select 他们想要通过以下方式订购记录的内容:
<form>
Order By:
<select name="sort">
<option value="firstname ASC">First Name (A - Z)</option>
<option value="firstname DESC">First Name (Z - A)</option>
<option value="surname ASC">Surname (A - Z)</option>
<option value="surname DESC">Surname (Z - A)</option>
<option value="email ASC">Email (A - Z)</option>
<option value="email DESC">Email (Z - A)</option>
<option value="max(recipients.contact_id) ASC">Emails Recieved (Low - High)</option>
<option value="max(recipients.contact_id) DESC">Emails Recieved (High - Low)</option>
<option value="updated_at ASC">Date Updated (Oldest First)</option>
<option value="updated_at DESC">Date Updated (Newest First)</option>
</select>
<button>
Go
</button>
</form>
试试这个。
@contacts = Contact.select('contacts.*, count(recipients.id) as emails_received')
.where(user_id: session[:user_id])
.joins(:recipients)
.group('contacts.id')
.order('emails_received ASC')
如果要显示未收到邮件的,需要left outer join。
@contacts = Contact.select('contacts.*, count(recipients.id) as emails_received')
.where(user_id: session[:user_id])
.joins('LEFT OUTER JOIN recipients ON recipients.contact_id = contacts.id)
.group('contacts.id')
.order('emails_received ASC')
为了进行 LEFT OUTER JOIN 试试这个:
Contact.includes(:recipients).references(:recipients)
注意:这也会预加载收件人并向查询添加大量 SQL
如果你也想进行排序,那么你应该可以这样做:
Contact.includes(:recipients).references(:recipients).group("contacts.id, recipients.id").order("COUNT(recipients.id) ASC")
我有一个用于发送电子邮件的 RoR 应用程序,我有联系人、收件人和用户模型,其中一个用户可以有多个联系人,一个联系人可以有多个收件人。数据如下所示:
User
ID Name
1 Ben
2 Emily
3 Brian
Contact
ID Name User_ID
1 Jack 1
2 Joe 2
3 Chloe 2
4 Jacob 1
5 Trevor 3
Recipient
ID Contact_ID Email_ID (not relevant for this question)
1 1 2
2 1 1
3 4 5
4 1 6
5 2 8
我想做的是在联系人的索引页上,显示属于一个用户的所有联系人,允许用户选择按什么排序,比如姓名和收到的电子邮件数量。
我遇到的问题是我可以毫无问题地显示属于一个用户的所有联系人,但我很难让用户根据他们收到的电子邮件数量对联系人进行排序。他们收到的电子邮件数量可以通过计算具有相同联系人 ID 的收件人数量来计算。我有这个问题的原因是因为我想显示属于用户的所有联系人,无论他们是否收到电子邮件(联系人可能收到 0 封电子邮件)。我试过的代码是:
@contacts = Contact.where(user_id: session[:user_id]).all.order(params.fetch(:sort, 'id asc'))
但这不允许用户按联系人收到的电子邮件数量进行排序。
我也试过这个:
@contacts = Contact.where(user_id: session[:user_id]).joins(:recipients).group('contacts.id').all.order(params.fetch(:sort, 'id asc'))
但这只显示已收到电子邮件的联系人。
我也试过这个:
@contacts = Contact.where(user_id: session[:user_id]).joins("LEFT OUTER JOIN contacts ON contacts.id = recipients.contact_id").all.order('max(recipients.contact_id) DESC')
这会显示所有已收到和未收到电子邮件的联系人并允许排序,但会显示重复数据。 IE。使用以上数据,如果 Ben 查看他的联系人 (user_id 1),他可以看到 Jack 和 Jacob,但是因为 Jack 收到了 3 封电子邮件,他会看到以下内容:
First Name:
Jack
Jacob
Jack
Jack
Jack
有办法解决吗?请注意,我目前在 index.html.erb
上使用以下代码以允许用户 select 他们想要通过以下方式订购记录的内容:
<form>
Order By:
<select name="sort">
<option value="firstname ASC">First Name (A - Z)</option>
<option value="firstname DESC">First Name (Z - A)</option>
<option value="surname ASC">Surname (A - Z)</option>
<option value="surname DESC">Surname (Z - A)</option>
<option value="email ASC">Email (A - Z)</option>
<option value="email DESC">Email (Z - A)</option>
<option value="max(recipients.contact_id) ASC">Emails Recieved (Low - High)</option>
<option value="max(recipients.contact_id) DESC">Emails Recieved (High - Low)</option>
<option value="updated_at ASC">Date Updated (Oldest First)</option>
<option value="updated_at DESC">Date Updated (Newest First)</option>
</select>
<button>
Go
</button>
</form>
试试这个。
@contacts = Contact.select('contacts.*, count(recipients.id) as emails_received')
.where(user_id: session[:user_id])
.joins(:recipients)
.group('contacts.id')
.order('emails_received ASC')
如果要显示未收到邮件的,需要left outer join。
@contacts = Contact.select('contacts.*, count(recipients.id) as emails_received')
.where(user_id: session[:user_id])
.joins('LEFT OUTER JOIN recipients ON recipients.contact_id = contacts.id)
.group('contacts.id')
.order('emails_received ASC')
为了进行 LEFT OUTER JOIN 试试这个:
Contact.includes(:recipients).references(:recipients)
注意:这也会预加载收件人并向查询添加大量 SQL
如果你也想进行排序,那么你应该可以这样做:
Contact.includes(:recipients).references(:recipients).group("contacts.id, recipients.id").order("COUNT(recipients.id) ASC")