Rails ActiveRecord基于第三个属性查询关系不存在的位置

时间:2014-08-27 05:27:55

标签: sql ruby-on-rails activerecord active-record-query

我有一个Adventure模型,它是DestinationUser之间的联接表(还有其他属性,例如zipcodetime_limit )。我想创建一个query,它会返回Destinations Adventure之间的Destination UserAdventure当前正在尝试创建User的{​​{1}} }} 不存在。

Adventure点击以启动新的Adventure时,应用的工作方式会创建user_idUserid&# 39; s Destination然后运行一种方法来提供随机Adventure.create(user_id: current_user.id),例如:

current_user.adventures.new(它实际上在做SQL queries)但同样的事情

我尝试过将原始.joins编写为使用Destination.joins(:adventures).where.not('adventures.user_id != ?'), user.id)的一些内容。以下是一些例子:

Destination.joins('LEFT OUTER JOIN adventure ON destination.id = adventure.destination_id').where('adventure.user_id != ?', user.id)

{{1}}

5 个答案:

答案 0 :(得分:6)

以下内容应返回用户在任何冒险中尚未访问过的所有目的地:

destinations = Destination.where('id NOT IN (SELECT destination_id FROM adventures WHERE user_id = ?)', user.id)

要选择随机的一个,请附加以下内容之一:

.all.sample
# or
.pluck(:id).sample

取决于您是想要完整记录还是只是id。

答案 1 :(得分:2)

不需要加入,这应该做:

Destination.where(['id not in ?', user.adventures.pluck(:destination_id)])

答案 2 :(得分:1)

在您的第一次尝试中,我看到使用where.not的等于运算符时遇到的问题。在你的第一次尝试中:

Destination.joins(:adventures).where.not('adventures.user_id != ?'), user.id)
你正在做where.not('adventures.user_id != ?'), user.id)。我明白这恰恰与你想要的相反,不是吗?您是否应该将其称为where.not('adventures.user_id = ?', user.id),即等于=

我认为以下查询适用于该要求:

Destination.joins(:adventures).where.not(adventures: { user_id: user.id })

我在第二种方法中看到的唯一问题是在destinationsadventures条件下使用joinwhere表格。表名应为复数。查询应该是:

Destination
.joins('LEFT OUTER JOIN adventures on destinations.id = adventures.destination_id')
.where('adventures.user_id != ?', user.id)

答案 3 :(得分:0)

ActiveRecord不会执行加入条件,但您可以使用用户destinations关系(例如has_many :destinations, through: adventures)作为子选择,从而产生WHERE NOT IN (SELECT...)

查询表达非常简单,不需要使用sql字符串shenanigans,多个查询或撤回临时的id组:

Destination.where.not(id: user.destinations)

如果您愿意,您还可以将上述条款与附加条款,排序和分组条款相关联。

答案 4 :(得分:0)

我使用this answerthis other answer混合解决了这个问题,并提出:

destination = Destination.where
                         .not(id: Adventure.where(user: user)
                                           .pluck(:destination_id)
                         )
                         .sample

.not(id: Adventure.where(user: user).pluck(:destination_id))部分排除了之前用户冒险中出现的目的地。

.sample部分将从结果中选择一个随机目的地。