You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

基于ActiveRecord的多分组多排序复杂Rails查询需求

问题描述

数据表结构

Poi.rb

belongs_to :poitable, polymorphic: true, optional: true, dependent: :destroy, touch: true
belongs_to :sleep, -> { where(pois: { poitable_type: 'Sleep' }) }, foreign_key: 'poitable_id'
belongs_to :town, -> { where(pois: { poitable_type: 'Town' }) }, foreign_key: 'poitable_id'

默认作用域:default_scope { includes(:type_poi) }

Sleep & Town 模型

has_one :poi, as: :poitable, dependent: :destroy
belongs_to :type_poi, inverse_of: :sleeps(或 :town)
has_many :poi_traces, dependent: :destroy
has_many :traces, through: :poi_traces, class_name: 'Trace'

PoiTrace.rb

class PoiTrace < ApplicationRecord
  belongs_to :poi
  belongs_to :trace
end

当前查询语句

Poi.left_joins(:town, :sleep)
             .joins(:poi_traces)
             .where(poi_traces: { poi_traces: { trace_id: [1, 2] }, length_to_paris: 1_370_000..1_520_000})
             .where(statut: [1, 2], poitable_type: ["Sleep", "Town"])
             .uniq

查询需求

  • 按 poi_traces.length_to_paris 排序
  • 按 pois.master_poi_id 分组
  • 按 pois.poitable_type 排序("Town" 类型优先)
  • 在每个分组内按 poi.poitable.type_poi 分组

期望结果格式

poi_trace.length_to_parismaster_poi_idpoitable_typepoi.poitable.type_poi
15202"Town""Town"
2"Sleep""Camping"
2"Sleep""Camping"
2"Sleep""Hotel"
2"Sleep""Hotel"
2"Sleep""Lodge"
15101"Town""Town"
1"Sleep""Camping"
1"Sleep""Camping"
1"Sleep""Hotel"
1"Sleep""Hotel"
1"Sleep""Lodge"
14904"Town""Town"
4"Sleep""Camping"
4"Sleep""Camping"

解决方案

修正后的查询语句

Poi.left_joins(:town, :sleep, poitable: :type_poi)
   .joins(:poi_traces)
   .where(
     poi_traces: { trace_id: [1, 2], length_to_paris: 1_370_000..1_520_000 },
     statut: [1, 2],
     poitable_type: ["Sleep", "Town"]
   )
   .order(
     'poi_traces.length_to_paris DESC',
     'pois.master_poi_id',
     "CASE pois.poitable_type WHEN 'Town' THEN 0 ELSE 1 END",
     'type_pois.name' # 此处根据type_poi表的实际名称字段调整,比如type字段
   )
   .group_by(&:master_poi_id)

关键说明

  1. 修正查询错误:原语句中poi_traces嵌套层级错误,已调整为正确的关联条件
  2. 排序逻辑:
    • 先按poi_traces.length_to_paris降序排列,匹配期望结果的顺序
    • 按master_poi_id分组排序
    • 用CASE表达式让"Town"类型优先于"Sleep"
    • 最后按关联的type_poi字段排序
  3. 分组处理:使用Ruby的group_by(&:master_poi_id)在内存中分组,保留分组内所有明细记录,符合展示需求
  4. 性能优化:通过left_joins(poitable: :type_poi)预加载关联数据,避免N+1查询

内容的提问来源于stack exchange,提问作者Ben

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.01 12:05:20