使用Rails的查询过滤has_many through



我在RoR上有一个关于多对多关系(has_many through:)的简单问题。所以我有一个Tweet模型,它有很多Tag,反之亦然。

你有一个索引操作和视图,在那里你可以显示所有带有标签的推文,但你也可以按标签进行过滤。还有一个小细节,Tweet可以不带标签。

所以如果我做这样的事情:

Tweet.includes(:tags).where(tags: { name: #2017 })

如果你过滤,你只会得到你过滤过的标签,但不会得到Tweet的所有标签。例如,如果Tweet有标签#2017, #2016, #2015,那么最终在您的视图中只会得到#2017

所以你可以通过这样做来解决问题:

Tweet.joins(:tags).where(tags: { name: #2017 })

然后你会得到每条推特的所有标签。

但问题是,若索引页面并没有过滤器,我希望所有的推文都显示出来,事件并没有标签。

当然,你可以做一个类似于检查标记参数是否存在的破解操作——做Tweet.joins,否则做Tweet.includes

有没有一种方法可以在1个查询内做到这一点而不需要破解?还有这背后的机制是什么。我理解includes or LEFT OUTER JOIN背后的逻辑,因为它只是将tweet_id和中间表中的"tag_id"映射到Tag表,当您有类似上面提到的where查询时。但是,为什么INNER JOIN让我一直给出所有标签,这让我产生了疑问。

谢谢你的回答。

这是因为当您查询时,includes会进行热切加载

Tweet.includes(:tags).where(tags: {name: "2017"})

它急切地加载所有标签名称为2017的推文。Tweet.tags将不会再次运行数据库查询,并且只有一个标记值。

但如果加入

Tweet.joins(:tags).where(tags: {name: "2017"})

它让innner加入,只找到那些有标签的推文,标签名称是2017。在执行Tweet.tags时找到tweets之后,它会再次运行db查询来查找所有相关的标签,从而为您提供所需的结果。

最新更新