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

Rails多列分组结果格式化及补全零值组合需求

为车辆API实现多分组嵌套结构并补全零值组合

当前车辆API仅支持单列分组查询,例如:

Vehicle.group(:fuel_type).count

返回格式符合API需求:

{
  "Petrol": 78,
  "Diesel": 22
}

但使用多列分组时,返回结果格式混乱,且缺失部分零值组合:

Vehicle.group(:fuel_type, :registration_status).count

返回的哈希键为字符串化的数组,且像Petrol + Exported这类无数据的组合直接缺失:

{
  "['Diesel', 'Scrapped']": 5,
  "['Petrol', 'Registered']": 6,
  "['Petrol', 'Scrapped']": 30,
  "['Diesel', 'Registered']": 1,
  "['Diesel', 'Deregistered']": 11,
  "['Petrol', 'Deregistered']": 42,
  "['Diesel', 'Exported']": 5
}

期望得到嵌套结构的结果,并补全所有可能的分组组合(包括计数为0的情况):

{
  "Diesel": {
    "Scrapped": 5,
    "Registered": 1,
    "Deregistered": 11,
    "Exported": 5
  },
  "Petrol": {
    "Scrapped": 30,
    "Registered": 6,
    "Deregistered": 42,
    "Exported": 0
  }
}

理想情况下支持任意n层嵌套分组,每层都显示所有可能的组合,计数为0的组合也需包含。


解决方案

核心思路

  1. 先获取每个分组字段的所有可能取值(枚举值或数据库中已存在的唯一值)
  2. 将原始多列分组的扁平哈希转换为嵌套结构
  3. 遍历所有可能的分组组合,补全缺失项并设置计数为0

基础实现(两列分组)

1. 获取分组字段的所有可能值

如果字段是Rails枚举类型,直接调用枚举的values方法:

# 假设Vehicle模型定义了对应enum
# enum fuel_type: { petrol: 'Petrol', diesel: 'Diesel' }
# enum registration_status: { registered: 'Registered', scrapped: 'Scrapped', deregistered: 'Deregistered', exported: 'Exported' }
fuel_types = Vehicle.fuel_types.values
statuses = Vehicle.registration_status.values

如果是普通字段,从数据库提取唯一值:

fuel_types = Vehicle.pluck(:fuel_type).uniq.compact
statuses = Vehicle.pluck(:registration_status).uniq.compact

2. 转换原始结果为嵌套哈希

raw_counts = Vehicle.group(:fuel_type, :registration_status).count

nested_counts = raw_counts.each_with_object({}) do |(keys, count), result|
  fuel_type, status = keys
  result[fuel_type] ||= {}
  result[fuel_type][status] = count
end

3. 补全零值组合

fuel_types.each do |fuel|
  statuses.each do |status|
    nested_counts[fuel] ||= {}
    nested_counts[fuel][status] ||= 0
  end
end

通用实现(支持n层分组)

编写递归方法处理任意层数的分组需求:

def build_nested_group_counts(model, group_fields)
  # 收集每个分组字段的所有可能值
  enum_values = group_fields.map do |field|
    # 优先处理Rails enum字段
    enum_method = field.to_s.pluralize
    if model.respond_to?(enum_method) && model.send(enum_method).is_a?(Hash)
      model.send(enum_method).values
    else
      # 普通字段从数据库取唯一值
      model.pluck(field).uniq.compact
    end
  end

  # 获取原始分组计数
  raw_counts = model.group(*group_fields).count

  # 递归构建全组合嵌套哈希
  fill_nested = lambda do |layers, data, path|
    if layers.size == 1
      # 底层:补全所有可能值,缺失则设为0
      layers.first.each_with_object({}) do |val, hash|
        hash[val] = data.fetch(path + [val], 0)
      end
    else
      # 递归处理上层节点
      layers.first.each_with_object({}) do |val, hash|
        hash[val] = fill_nested.call(layers[1..-1], data, path + [val])
      end
    end
  end

  fill_nested.call(enum_values, raw_counts, [])
end

使用示例

# 两列分组
build_nested_group_counts(Vehicle, [:fuel_type, :registration_status])

# 三列分组(添加body_type字段)
build_nested_group_counts(Vehicle, [:fuel_type, :registration_status, :body_type])

这个方法会自动生成嵌套结构的哈希,补全所有可能的分组组合,无数据的组合计数设为0,完全适配API响应格式。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.06 04:20:31