Sql 在给定潜在成员时查找现有消息组

Sql 在给定潜在成员时查找现有消息组,sql,ruby-on-rails,postgresql,activerecord,Sql,Ruby On Rails,Postgresql,Activerecord,我有一个应用程序,用户可以在其中创建消息组。MessageGroup通过MessageMemberships拥有成员。MessageMemberships属于“profile”,这是多态的,因为它们在数据库中是不同类型的“profile” 消息组 类MessageGroup

我有一个应用程序,用户可以在其中创建消息组。MessageGroup通过MessageMemberships拥有成员。MessageMemberships属于“profile”,这是多态的,因为它们在数据库中是不同类型的“profile”

消息组

类MessageGroup class MessageMembership
您将如何查询它?

下面未测试的代码假定:

您已经或可以向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