具有2种不同连接条件的Ruby查询

gwa*_*ton 10 ruby mysql ruby-on-rails jointable

我想查找具有特定LanguagesUsers记录的所有用户.目前我正在尝试查询连接表,LanguagesUsers用于用户具有2个相应的languages_id和级别的所有实例

要找到只有一个关联的位置,这有效:

User.joins(:languages_users).where(languages_users: {language_id: 2, level: 5})
Run Code Online (Sandbox Code Playgroud)

如何在查询中包含2个languages_users,它们是真的?(例如,我想language_id: 2 level: 1language_id: 3 level: 5)

我试过这个,但它返回一个错误:

User.joins(:languages_users).where(languages_users: {language_id: 2, level: 5} AND languages_users: {language_id: 1, level: 3})
Run Code Online (Sandbox Code Playgroud)

这个返回一个空数组,即使肯定有2个languages_users符合此条件的用户:

User.joins(:languages_users).where(languages_users: {language_id: 2, level: 5}).where(languages_users: {language_id: 1, level: 3})
Run Code Online (Sandbox Code Playgroud)

这是什么格式?谢谢!!

更新:LanugagesUser是语言和用户之间的连接表,具有language_id,level,user_id

gem 'sqlite3', group: :development
group :production do
    gem 'pg'
    gem 'rails_12factor'
end
Run Code Online (Sandbox Code Playgroud)

更新2:由于两个答案都提出了一个或一个陈述,我认为我没有正确地传达这个事实:

两个记录很多.例如.我想知道用户有什么语言用户(language_id:1,级别:5)和LanguagesUser(language_id:2,级别:1)

sou*_*dog 2

你试过了吗:

User.joins(:languages_users).where(languages_users: [{language_id: 2, level: 5}, {language_id: 1, level: 3}])
Run Code Online (Sandbox Code Playgroud)

编辑:由于您使用的是 ActiveRecord >= 5,因此可以使用.or语法。结果有点冗长,但它应该可以工作,而且我相信你可以美化它:

User.joins(:languages_users).where(
  languages_users: {language_id: 2, level: 5}).
  or(
    User.joins(:languages_users).where(
      languages_users: {language_id: 1, level: 3}
  )
Run Code Online (Sandbox Code Playgroud)

编辑2:我我明白你现在要做什么,比我最初想象的更复杂,但我认为你将需要一个嵌套查询。如果您首先查询该languages_users表并按 进行分组user_id,则可以HAVING对其应用子句来查找使用两种语言的用户。然后,您从该查询中选择 user_ids 并在 users 表的简单查询中使用它们。由于您使用的是 postgres,因此以下内容可能有效。

languages = [{ language_id: 2, level: 5 }, { language_id: 1, level: 3 }]
User.where(users_with_all_languages(languages)

def users_with_all_languages(languages)
  LanguagesUser.
    select(:user_id).
    group(:user_id).
    having('array_agg(language_id) @> ARRAY[?] AND array_agg(level) @> ARRAY[?]',
      languages.map { |x| x[:language_id] },
      languages.map { |x| x[:level] }
    )
end
Run Code Online (Sandbox Code Playgroud)

或者,更简单的是,如果您对语言数据的格式具有灵活性:

language_ids = [2, 1]
language_levels = [5, 3]
User.where(users_with_all_languages(language_ids, language_levels)

def users_with_all_languages(ids, levels)
  LanguagesUser.
    select(:user_id).
    group(:user_id).
    having('array_agg(language_id) @> ARRAY[?] AND array_agg(level) @> ARRAY[?]', ids, levels)
end
Run Code Online (Sandbox Code Playgroud)

我做了类似的事情,但没有在连接表上使用两个条件,因此我认为AND这两个array_agg条件是唯一的通配符......