Sql 在给定潜在成员时查找现有消息组
我有一个应用程序,用户可以在其中创建消息组。MessageGroup通过MessageMemberships拥有成员。MessageMemberships属于“profile”,这是多态的,因为它们在数据库中是不同类型的“profile” 消息组 类MessageGroupSql 在给定潜在成员时查找现有消息组,sql,ruby-on-rails,postgresql,activerecord,Sql,Ruby On Rails,Postgresql,Activerecord,我有一个应用程序,用户可以在其中创建消息组。MessageGroup通过MessageMemberships拥有成员。MessageMemberships属于“profile”,这是多态的,因为它们在数据库中是不同类型的“profile” 消息组 类MessageGroup
您将如何查询它?下面未测试的代码假定: 您已经或可以向message\u groups表中添加message\u memberships\u count counter\u cache列。也许还可以在message\u memberships\u count列中添加一个索引来加速查询 您在message_memberships表中有适当的唯一索引,这将防止配置文件多次添加到同一message_组 工作原理: 有一个循环将在同一个表上执行多个内部联接,以确保每个概要文件都存在关联 然后,查询将检查组中的成员总数是否等于配置文件数
根据@AbM的回答,我得出以下结论。这与前面的答案具有相同的假设,计数器缓存和唯一索引应该到位
def self.find_direct_with_profiles!(profiles)
# Not present, some authorization checks that may raise (hence the bang method name)
# Loop through the profiles and join them all together so we get a join that contains
# all the data we need in order to filter it down
join = ""
conditions = ""
profiles.each_with_index do |profile, index|
klass = profile.class.name
# provide an alias to the table to prevent `PG::DuplicateAlias: ERROR
table_alias = "message_memberships_#{Digest::SHA1.hexdigest("#{klass}_#{profile.id}")[0..6]}"
join += " INNER JOIN \"message_memberships\" \"#{table_alias}\" ON \"#{table_alias}\".\"message_group_id\" = \"message_groups\".\"id\""
condition_join = index == 0 ? 'where' : ' and'
conditions += "#{condition_join} \"#{table_alias}\".\"profile_type\" = '#{klass}' and \"#{table_alias}\".\"profile_id\" = #{profile.id}"
end
# Add one
size_conditional = " and \"message_groups\".\"message_memberships_count\" = #{profiles.size}"
# Add any other conditions you may need
conditions += "#{size_conditional}"
query = "SELECT \"message_groups\".* FROM \"message_groups\" #{join} #{conditions}"
# find_by_sql returns an array with hydrated models from the select statement. In this case I am just grabbing the first one to match other finder active record method conventions
self.find_by_sql(query).first
end
谢谢,我想这应该行得通。我明天会玩它,然后会转回来接受这个。计数器缓存解决了很多我挂断的问题!感谢AbM,基于以上答案,我现在有了一个有效的解决方案。我将在下面发布我的测试解决方案以供参考,但接受你的解决方案,因为你解决了它。
def self.find_direct_with_profiles!(profiles)
# Not present, some authorization checks that may raise (hence the bang method name)
# Loop through the profiles and join them all together so we get a join that contains
# all the data we need in order to filter it down
join = ""
conditions = ""
profiles.each_with_index do |profile, index|
klass = profile.class.name
# provide an alias to the table to prevent `PG::DuplicateAlias: ERROR
table_alias = "message_memberships_#{Digest::SHA1.hexdigest("#{klass}_#{profile.id}")[0..6]}"
join += " INNER JOIN \"message_memberships\" \"#{table_alias}\" ON \"#{table_alias}\".\"message_group_id\" = \"message_groups\".\"id\""
condition_join = index == 0 ? 'where' : ' and'
conditions += "#{condition_join} \"#{table_alias}\".\"profile_type\" = '#{klass}' and \"#{table_alias}\".\"profile_id\" = #{profile.id}"
end
# Add one
size_conditional = " and \"message_groups\".\"message_memberships_count\" = #{profiles.size}"
# Add any other conditions you may need
conditions += "#{size_conditional}"
query = "SELECT \"message_groups\".* FROM \"message_groups\" #{join} #{conditions}"
# find_by_sql returns an array with hydrated models from the select statement. In this case I am just grabbing the first one to match other finder active record method conventions
self.find_by_sql(query).first
end