我有一个带有Postgres数据库的Rails应用,该数据库具有一个带jsonb genres
列的Artists表。
有成千上万的行。
该行中的每个类型列都有一个类似["rock", "indie", "seen live", "alternative", "indie rock"]
的数组,具有不同类型。
我想做的是在所有行中输出JSON中每个流派的计数。
类似于:{"rock": 532, "power metal": 328, "indie": 862}
有没有办法有效地做到这一点?
更新...这是我目前所拥有的...
genres = Artist.all.pluck(:genres).flatten.delete_if &:empty?
output = Hash[genres.group_by {|x| x}.map {|k,v| [k,v.count]}]
final = output.sort_by{|k,v| v}.to_h
输出是哈希而不是JSON,这很好。
但是已经感觉很慢了,所以我想知道是否有更好的方法可以做到这一点。
最佳答案
如果仅使用体面的关系数据库设计,这是一项极其琐碎的任务:
class Artist < ApplicationRecord
has_many :artist_genres
has_many :genres, through: :artist_genres
end
class Genre < ApplicationRecord
has_many :artist_genres
has_many :artists, through: :artist_genres
end
class ArtistGenre < ApplicationRecord
belongs_to :artist
belongs_to :genre
end
然后,您可以通过以下方式获得结果:
class Genre < ApplicationRecord
has_many :artist_genres
has_many :genres, through: :artist_genres
# This will instanciate a record for each row just like your average scope
# and return a ActiveRecord::Relation object.
def self.with_artist_counts
self.joins(:artist_genres)
.select('genres.name, COUNT(artist_genres.id) AS artists_count')
.group(:id)
end
# This pulls the columns as raw sql results and creates a hash with the genre
# name as keys
def self.pluck_artist_counts
self.connection.select_all(with_artist_counts.to_sql).inject({}) do |hash, row|
hash.merge(row["name"] => row["artists_count"])
end
end
end