[英]Rails ActiveRecord query where relationship does not exist based on third attribute
I have an Adventure
model, which is a join table between a Destination
and a User
(and has additional attributes such as zipcode
and time_limit
).我有一个
Adventure
模型,它是Destination
和User
之间的连接表(并且具有其他属性,例如zipcode
和time_limit
)。 I want to create a query
that will return me all the Destinations
where an Adventure
between that Destination
and the User
currently trying to create an Adventure
does not exist.我想创建一个
query
,将返回我所有的Destinations
,其中的Adventure
是与Destination
和User
目前正试图创建一个Adventure
不存在。
The way the app works when a User
clicks to start a new Adventure
it will create that Adventure
with the user_id
being that User
's id
and then runs a method to provide a random Destination
, ex:应用程序工作时的方式
User
点击开始新的Adventure
,将创建一个Adventure
与user_id
在于User
的id
,然后运行方法来提供一个随机Destination
,例如:
Adventure.create(user_id: current_user.id)
(it is actually doing current_user.adventures.new
) but same thing Adventure.create(user_id: current_user.id)
(它实际上是在做current_user.adventures.new
)但同样的事情
I have tried a few things from writing raw SQL queries
to using .joins
.我尝试了一些方法,从编写原始
SQL queries
到使用.joins
。 Here are a few examples:这里有一些例子:
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)
The below should return all destinations that user has not yet visited in any of his adventures:下面应该返回用户在他的任何冒险中还没有访问过的所有目的地:
destinations = Destination.where('id NOT IN (SELECT destination_id FROM adventures WHERE user_id = ?)', user.id)
To select a random one append one of:要随机选择一个附加以下之一:
.all.sample
# or
.pluck(:id).sample
Depending on whether you want a full record or just id.取决于您是想要完整记录还是只是 id。
不需要加入,这应该做:
Destination.where(['id not in ?', user.adventures.pluck(:destination_id)])
In your first attempt, I see the problem to be in the usage of equality operator with where.not
.在您的第一次尝试中,我发现问题在于使用
where.not
的相等运算符。 In your first attempt:在您的第一次尝试中:
Destination.joins(:adventures).where.not('adventures.user_id != ?'), user.id)
you're doing where.not('adventures.user_id != ?'), user.id)
.你在做什么
where.not('adventures.user_id != ?'), user.id)
。 I understand this is just the opposite of what you want, isn't it?我知道这与您想要的正好相反,不是吗? Shouldn't you be calling it as
where.not('adventures.user_id = ?', user.id)
, ie with an equals =
?您不应该将其称为
where.not('adventures.user_id = ?', user.id)
,即使用 equals =
吗?
I think the following query would work for the requirement:我认为以下查询可以满足要求:
Destination.joins(:adventures).where.not(adventures: { user_id: user.id })
The only problem I see in your second method is the usage of destinations
and adventures
table in both join
and where
conditions.我在您的第二种方法中看到的唯一问题是在
join
和where
条件中使用destinations
和adventures
表。 The table names should be plural.表名应该是复数。 The query should have been:
查询应该是:
Destination
.joins('LEFT OUTER JOIN adventures on destinations.id = adventures.destination_id')
.where('adventures.user_id != ?', user.id)
ActiveRecord doesn't do join conditions but you can use your User destinations
relation (eg a has_many :destinations, through: adventures
) as a sub select which results in a WHERE NOT IN (SELECT...)
ActiveRecord 不执行连接条件,但您可以使用您的用户
destinations
关系(例如has_many :destinations, through: adventures
)作为子选择,这会导致WHERE NOT IN (SELECT...)
The query is pretty simple to express and doesn't require using sql string shenanigans, multiple queries or pulling back temporary sets of ids:该查询表达起来非常简单,不需要使用 sql 字符串恶作剧、多个查询或拉回临时 id 集:
Destination.where.not(id: user.destinations)
If you want you can also chain the above realation with additional where terms, ordering and grouping clauses.如果您愿意,您还可以将上述实现与附加的 where 项、排序和分组子句联系起来。
I solved this problem with a mix of this answer and this other answer and came out with:我用这个答案和另一个答案的混合解决了这个问题,并得出了:
destination = Destination.where
.not(id: Adventure.where(user: user)
.pluck(:destination_id)
)
.sample
The .not(id: Adventure.where(user: user).pluck(:destination_id))
part excludes destinations present in previous adventures of the user. .not(id: Adventure.where(user: user).pluck(:destination_id))
部分排除了用户之前冒险中出现的目的地。
The .sample
part will pick a random destination from the results. .sample
部分将从结果中随机选择一个目的地。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.