ruby 关于 rails 过滤 pg_search_scope v2.2
ruby on rails filtering pg_search_scope v2.2
我在 Rails 上对 Ruby 还很陌生,我需要帮助弄清楚如何修改现有的数据库查询。我使用的是无法更新的旧版本:Ruby 2.2.3p173 和 Rails 4.0.2.
我想过滤现有的查询结果,去除没有视频的记录。我认为的模型层次结构是:Artist、AlbumGroup、Album、Track、Video。
澄清一下:我想要至少有 1 个视频的艺术家,来自模型协会艺术家->专辑组->专辑->曲目->视频(不是艺术家->视频)。
现有查询包含在模型艺术家中:
require_dependency "tagging"
require_dependency "similar"
class Artist < ActiveRecord::Base
has_many :images, dependent: :destroy
has_many :taggings, dependent: :destroy
has_many :artforms, through: :taggings
has_many :similars, foreign_key: "similar_id", dependent: :destroy
has_many :similar_artists, through: :similars, source: :similar_to
has_many :reverse_similars, foreign_key: "similar_to_id", class_name: "Similar", dependent: :destroy
has_many :similar_to_artists, through: :reverse_similars, source: :similar
has_many :memberships, foreign_key: "member_id", dependent: :destroy
has_many :groups, through: :memberships, source: :membership
has_many :group_members, foreign_key: "membership_id", class_name: "Membership", dependent: :destroy
has_many :members, through: :group_members, source: :member
has_many :users, through: :followed_artists
has_many :videos, dependent: :destroy
has_many :audios, dependent: :destroy
has_many :metrics, through: :audios
has_many :releases, foreign_key: 'artist_id', class_name: "AlbumGroup"
has_many :albums
has_many :collaborations
has_many :album_groups, through: :collaborations
mount_uploader :mugshot, MugshotUploader
include PgSearch
pg_search_scope :for_name,
against: :name,
using: { tsearch: {threshold: '1', dictionary: 'simple', tsvector_column: 'tsv_name', prefix: true, normalization: 2}},
ranked_by: "(artists.popularity / 50 * :tsearch) + :tsearch"
end
我想添加类似下面的内容来过滤掉没有任何视频的记录:(到查询):
if: artist.releases.albums.tracks.videos.count > 1
或者艺术家模型?:
scope :valid, -> {where("video_count > 1")}
不同型号的其他代码如下:
class AlbumGroup < ActiveRecord::Base
belongs_to :artist
has_many :collaborations
has_many :artists, through: :collaborations
has_many :albums
has_many :taggings, dependent: :destroy
has_many :artforms, through: :taggings
mount_uploader :artwork, MugshotUploader
def as_json options={}
{
id: id,
title: title
}
end
end
class Album < ActiveRecord::Base
belongs_to :album_group
belongs_to :artist
has_many :tracks
end
class Track < ActiveRecord::Base
has_many :playlist_tracks, dependent: :destroy
has_many :playlists, through: :playlist_tracks
belongs_to :audio
belongs_to :video
has_many :videos
has_many :audios
has_many :taggings, dependent: :destroy
has_many :artforms, through: :taggings
belongs_to :album
belongs_to :artist
default_scope order: "position ASC"
after_save :cache_columns
def cache_columns
if image_url.nil?
img = album.album_group.artwork_url(:tiny)
unless img.nil?
update_column(:image_url,img)
end
end
if artist_name.nil?
if artist_id
name = Artist.find(artist_id).name
update_column(:artist_name,name)
end
end
if album_name.nil?
if album_id
title = Album.find(album_id).title
update_column(:album_name,title)
end
end
end
end
class Video < ActiveRecord::Base
belongs_to :artist
belongs_to :event
belongs_to :track
has_many :tracks
has_many :playlists, through: :tracks, order: "tracks.position ASC"
scope :valid, -> {where("flag_count < 2").order("score DESC") }
scope :flagged, -> {where("flag_count > ?", 1) }
# validates :url, uniqueness: {scope: :artist_id}
end
ActiveRecord 的 has_many
和 belongs_to
方法使您能够直接在关联上定义范围。这样就可以自定义访问关联时生成的SQL
假设您想在艺术家模型上定义一个范围,returns 所有拥有零个视频的艺术家。在Rails 5,要查找所有没有视频的艺术家,可以使用left_outer_joins
class Artist < ActiveRecord::Base
has_many :videos
scope :with_zero_videos, -> { left_outer_joins(:videos).where(videos: {id: nil}) }
end
另一个好的解决方案是像这样使用 includes
:
Artist.includes(:videos).where(videos: { videos_id: nil })
你可以选择你最喜欢的!
希望对您有所帮助。
谢谢 Gabriel,我向 artists_controller.rb 添加了一个原始 SQL 查询,它看起来像:
def index
#artists = Artist.for_name(params[:name])
artists = Artist.find_by_sql ["SELECT artists.*, ((artists.popularity / 50 * (ts_rank((artists.tsv_name), (to_tsquery('simple', ''' ' || ? || ' ''' || ':*')), 2))) + (ts_rank((artists.tsv_name), (to_tsquery('simple', ''' ' || ? || ' ''' || ':*')), 2))) AS pg_search_rank FROM artists " +
"JOIN album_groups on (artists.id = album_groups.artist_id) " +
"JOIN tracks on (tracks.album_group_id = album_groups.id) " +
"JOIN videos on (videos.track_id = tracks.id) " +
"WHERE (((artists.tsv_name) @@ (to_tsquery('simple', ''' ' || ? || ' ''' || ':*')))) " +
"GROUP BY artists.id " +
"ORDER BY pg_search_rank DESC, artists.id ASC", params[:name], params[:name], params[:name]]
render json: artists, each_serializer: SimpleArtistSerializer
end
我在 Rails 上对 Ruby 还很陌生,我需要帮助弄清楚如何修改现有的数据库查询。我使用的是无法更新的旧版本:Ruby 2.2.3p173 和 Rails 4.0.2.
我想过滤现有的查询结果,去除没有视频的记录。我认为的模型层次结构是:Artist、AlbumGroup、Album、Track、Video。
澄清一下:我想要至少有 1 个视频的艺术家,来自模型协会艺术家->专辑组->专辑->曲目->视频(不是艺术家->视频)。
现有查询包含在模型艺术家中:
require_dependency "tagging"
require_dependency "similar"
class Artist < ActiveRecord::Base
has_many :images, dependent: :destroy
has_many :taggings, dependent: :destroy
has_many :artforms, through: :taggings
has_many :similars, foreign_key: "similar_id", dependent: :destroy
has_many :similar_artists, through: :similars, source: :similar_to
has_many :reverse_similars, foreign_key: "similar_to_id", class_name: "Similar", dependent: :destroy
has_many :similar_to_artists, through: :reverse_similars, source: :similar
has_many :memberships, foreign_key: "member_id", dependent: :destroy
has_many :groups, through: :memberships, source: :membership
has_many :group_members, foreign_key: "membership_id", class_name: "Membership", dependent: :destroy
has_many :members, through: :group_members, source: :member
has_many :users, through: :followed_artists
has_many :videos, dependent: :destroy
has_many :audios, dependent: :destroy
has_many :metrics, through: :audios
has_many :releases, foreign_key: 'artist_id', class_name: "AlbumGroup"
has_many :albums
has_many :collaborations
has_many :album_groups, through: :collaborations
mount_uploader :mugshot, MugshotUploader
include PgSearch
pg_search_scope :for_name,
against: :name,
using: { tsearch: {threshold: '1', dictionary: 'simple', tsvector_column: 'tsv_name', prefix: true, normalization: 2}},
ranked_by: "(artists.popularity / 50 * :tsearch) + :tsearch"
end
我想添加类似下面的内容来过滤掉没有任何视频的记录:(到查询):
if: artist.releases.albums.tracks.videos.count > 1
或者艺术家模型?:
scope :valid, -> {where("video_count > 1")}
不同型号的其他代码如下:
class AlbumGroup < ActiveRecord::Base
belongs_to :artist
has_many :collaborations
has_many :artists, through: :collaborations
has_many :albums
has_many :taggings, dependent: :destroy
has_many :artforms, through: :taggings
mount_uploader :artwork, MugshotUploader
def as_json options={}
{
id: id,
title: title
}
end
end
class Album < ActiveRecord::Base
belongs_to :album_group
belongs_to :artist
has_many :tracks
end
class Track < ActiveRecord::Base
has_many :playlist_tracks, dependent: :destroy
has_many :playlists, through: :playlist_tracks
belongs_to :audio
belongs_to :video
has_many :videos
has_many :audios
has_many :taggings, dependent: :destroy
has_many :artforms, through: :taggings
belongs_to :album
belongs_to :artist
default_scope order: "position ASC"
after_save :cache_columns
def cache_columns
if image_url.nil?
img = album.album_group.artwork_url(:tiny)
unless img.nil?
update_column(:image_url,img)
end
end
if artist_name.nil?
if artist_id
name = Artist.find(artist_id).name
update_column(:artist_name,name)
end
end
if album_name.nil?
if album_id
title = Album.find(album_id).title
update_column(:album_name,title)
end
end
end
end
class Video < ActiveRecord::Base
belongs_to :artist
belongs_to :event
belongs_to :track
has_many :tracks
has_many :playlists, through: :tracks, order: "tracks.position ASC"
scope :valid, -> {where("flag_count < 2").order("score DESC") }
scope :flagged, -> {where("flag_count > ?", 1) }
# validates :url, uniqueness: {scope: :artist_id}
end
ActiveRecord 的 has_many
和 belongs_to
方法使您能够直接在关联上定义范围。这样就可以自定义访问关联时生成的SQL
假设您想在艺术家模型上定义一个范围,returns 所有拥有零个视频的艺术家。在Rails 5,要查找所有没有视频的艺术家,可以使用left_outer_joins
class Artist < ActiveRecord::Base
has_many :videos
scope :with_zero_videos, -> { left_outer_joins(:videos).where(videos: {id: nil}) }
end
另一个好的解决方案是像这样使用 includes
:
Artist.includes(:videos).where(videos: { videos_id: nil })
你可以选择你最喜欢的!
希望对您有所帮助。
谢谢 Gabriel,我向 artists_controller.rb 添加了一个原始 SQL 查询,它看起来像:
def index
#artists = Artist.for_name(params[:name])
artists = Artist.find_by_sql ["SELECT artists.*, ((artists.popularity / 50 * (ts_rank((artists.tsv_name), (to_tsquery('simple', ''' ' || ? || ' ''' || ':*')), 2))) + (ts_rank((artists.tsv_name), (to_tsquery('simple', ''' ' || ? || ' ''' || ':*')), 2))) AS pg_search_rank FROM artists " +
"JOIN album_groups on (artists.id = album_groups.artist_id) " +
"JOIN tracks on (tracks.album_group_id = album_groups.id) " +
"JOIN videos on (videos.track_id = tracks.id) " +
"WHERE (((artists.tsv_name) @@ (to_tsquery('simple', ''' ' || ? || ' ''' || ':*')))) " +
"GROUP BY artists.id " +
"ORDER BY pg_search_rank DESC, artists.id ASC", params[:name], params[:name], params[:name]]
render json: artists, each_serializer: SimpleArtistSerializer
end