简体   繁体   English

使用连接和分组的 Active Record 查询

[英]Active Record querying with joins and group by

I'm designing an API to get data from the following scenario :我正在设计一个 API 来从以下场景中获取数据:

brands table : brands表:

+------------+--------------+------+-----+---------+----------------+
| Field      | Type         | Null | Key | Default | Extra          |
+------------+--------------+------+-----+---------+----------------+
| id         | bigint(20)   | NO   | PRI | NULL    | auto_increment |
| name       | varchar(255) | YES  |     | NULL    |                |
+------------+--------------+------+-----+---------+----------------+

items table : items表:

+---------------------------+--------------+------+-----+---------+----------------+
| Field                     | Type         | Null | Key | Default | Extra          |
+---------------------------+--------------+------+-----+---------+----------------+
| id                        | bigint(20)   | NO   | PRI | NULL    | auto_increment |
| category_id               | bigint(20)   | YES  | MUL | NULL    |                |
| brand_id                  | bigint(20)   | YES  |     | NULL    |                |
+---------------------------+--------------+------+-----+---------+----------------+

item_skus table : item_skus表:

+---------------------------+--------------+------+-----+---------+----------------+
| Field                     | Type         | Null | Key | Default | Extra          |
+---------------------------+--------------+------+-----+---------+----------------+
| id                        | bigint(20)   | NO   | PRI | NULL    | auto_increment |
| item_id                   | bigint(20)   | YES  | MUL | NULL    |                |
| number_of_stock           | int(11)      | YES  |     | NULL    |                |
+---------------------------+--------------+------+-----+---------+----------------+

Item model association with ItemSku and Brand ItemSkuBrand Item模型关联

  belongs_to :brand
  has_many :skus, class_name: 'ItemSku'

Simply i want the counts of stock available items and all items for each brand.只是我想要每个品牌的库存可用商品和所有商品的数量。

{
  "brandCounts":[
    {
       "id":7006,
       "name":"Brand 01",
       "stockAvailableItemCount":50,
       "allItemCount":60
    },
    {
       "id":20197,
       "name":"Brand 02"
       "availableItemCount":150,
       "allItemCount":660
    }
  ]
}

Implementation :执行 :

brand_counts = []
brand_counts_hash = Hash.new()
items = Item.left_outer_joins(:skus).where(category_id: params[:id]).pluck(:brand_id, :number_of_stock, :item_id)

items.each do |item|
  brand_id = item[0]
  stock = item[1]

  if brand_counts_hash.has_key?(brand_id)
    item_count_arry = brand_counts_hash[brand_id]
    stock_available_item_count = item_count_arry[0]
    all_item_count = item_count_arry[1]
    if stock > 0
      brand_counts_hash[brand_id] = [stock_available_item_count + 1, all_item_count + 1]
    else
      brand_counts_hash[brand_id] = [stock_available_item_count, all_item_count + 1]
    end
  else
    stock_available_item_count = 0
    all_item_count = 0
    if stock > 0
      stock_available_item_count += 1
      all_item_count += 1
      brand_counts_hash[brand_id] = [stock_available_item_count, all_item_count]
    else
      all_item_count += 1
      brand_counts_hash[brand_id] = [stock_available_item_count, all_item_count]
    end
  end
end

brand_counts_hash.each do |key, value|
  stock_available_item_count = value[0]
  all_item_count = value[1]
  brand_counts << {
    id: key,
    name: get_brand_name(key),
    stock_available_item_count: stock_available_item_count,
    all_item_count: all_item_count
  }
  end
  @brand_counts = brand_counts
  render 'brands/counts/index', formats: :json
end

def get_brand_name(brand_id)
  brand = Brand.find_by(id: brand_id)
  brand.name unless brand == nil
end

Is there a way to optimize this further without multiple loops maybe?有没有办法在没有多个循环的情况下进一步优化?

Assume your Brand model also has the following association defined假设您的Brand模型还定义了以下关联

has_many :items

and the final result you want is like你想要的最终结果就像

{
  "brandCounts":[
    {
       "id":7006,
       "name":"Brand 01",
       "stockAvailableItemCount":50,
       "allItemCount":60
    },
    {
       "id":20197,
       "name":"Brand 02"
       "availableItemCount":150,
       "allItemCount":660
    }
  ]
}

The following code may not work when you copy and paste to your project.当您复制并粘贴到您的项目时,以下代码可能不起作用。 But it demonstrate how this problem can be solved with less code但它展示了如何用更少的代码解决这个问题

Brand.includes(items: :skus).all.map do |brand|
  {
    id: brand.id,
    name: brand.name,
    stockAvailableItemCount: brand.items.count,
    allItemCount: brand.items.map {|item| item.skus.sum(:number_of_stock)}.sum
  }
end

if you need json format, just use to_json to the result of above code.如果您需要json格式,只需将to_json用于上述代码的结果。

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

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