【问题标题】:Finding all entries where a collection field contains any of the given items查找集合字段包含任何给定项目的所有条目
【发布时间】:2024-04-25 01:10:01
【问题描述】:

我有一个 Spring Boot 应用程序,其中包含这样的实体(为了紧凑而剥离了一些字段):

@Entity
public class Message extends AbstractPersistable<Long> {
    @ManyToMany(targetEntity = Tag.class, fetch = FetchType.EAGER)
    private Set<Tag> tags;
    // getter and setter for tags here
}

Tag 只是一个带有名称字段的简单实体。


现在,我的代码中有另一个Set&lt;Tag&gt; 从用户那里获得。我想找到所有Messages 在这个集合中有任何标签。例如,如果我们有以下消息:

ID    TAGS
1     1, 2, 3
2     2, 5, 7
3     2, 4, 7

那么查询应该,给定集合 [3, 4] 返回消息 1 和 3。


我尝试编写此存储库:

public interface MessageRepository extends JpaRepository<Message, Long> {
    List<Message> findByTags(Set<Tag> tag);
}

我启用了query logging 并且我的代码产生了一个查询,我在此处进行了一些清理。在我尝试的情况下,查询没有产生任何结果,我不知道scalar = array 比较在做什么。

SELECT message.id AS id FROM message
LEFT OUTER JOIN message_tags ON message.id = message_tags.message_id
LEFT OUTER JOIN tag ON message_tags.tags_id = tag.id
WHERE tag.id = (1,2,3,4,5) -- this is the input set

按照@AliDehghani 的建议,我尝试将方法编写为findByTagsIn(Set&lt;Tag&gt; tag)。这将查询中的最后一个 = 替换为 in

我得到了结果,但还有另一个问题:每个匹配的标签都会重复结果,就像人们可能从查询中猜到的那样。例如,使用上面的示例消息搜索 [2, 7] 将返回消息 1、消息 2 和消息 3 两次。

据我所知,在这里添加某种 GROUP BY 子句可能会有所帮助。


predefined query method keywords 似乎也没有任何与此相关的功能,所以我想我必须使用@Query 或其他东西编写自己的功能。

我似乎也想不出一个可行的查询,而且我在 H2 方面的经验也不是很丰富,所以我也不想猜测它是如何工作的。

我不想编写一个方法来查找具有单个标签的所有消息,为每个标签调用它并组合结果,因为这会很丑陋,并且给定大量标签作为输入,非常慢。我应该如何编写我的查询方法?

【问题讨论】:

  • 你试过findByOpinionsIn(Set&lt;Tag&gt; tags)吗?
  • @AliDehghani 这让我得到了结果,但它们会针对每个匹配的标签重复。
  • 什么意思?您不止一次收到一些消息?
  • @AliDehghani 我更新了问题。基本上,如果一条消息与参数列表中的多个标签匹配,它会为每个标签再次返回该消息。
  • @AliDehghani 成功了。将其发布为答案,我会接受。

标签: java spring spring-data-jpa h2


【解决方案1】:

列出 findByTags(设置标签);

从查询日志中可以看出,这种查询方法只会找到给定tag参数中所有标签都被标记的消息,这不是你想要的。

为了找到带有这些标签的消息,您可以使用以下查询方法:

List<Message> findByTagsIn(Set<Tag> tag);

我得到了结果,但还有另一个问题:结果是 为每个匹配的标签重复,就像人们可能从查询中猜测的那样。

为了摆脱那些重复的消息,您只能获取不同的值:

List<Message> findDistinctByTagsIn(Set<Tag> tag);

【讨论】: