简体   繁体   中英

Spring Data with strict In-clause

See updated question below

I want to query for elements where every element is required to have all given attributes of eg a set to be returned, not only one.

Default Spring Data Jpa Query, where one attribute is enough:

findAllByAttributeIn(Set<Attribute> setAttr)

Example problem

For these elements (abstracted, no actual table)

id | attr
----------
1  | A
2  | A,B
3  | A,B,C

with this filter:

setAttr: [A,B]

the default query

findAllByAttributeIn(Set<Attribute> setAttr)

returns all elements (by ids):

[1,2,3]

Desired result is only the second element (with [A,B]).

Is that possible with the given Spring Data Jpa query keywords or is the only solution to create a custom query?

Updated question:

There are two entities, Media and Tag. They have a many-to-many relationship which is realised in the table Media_has_tags. Every media can have any number of tags (0..*). So in my Spring app, media has a set of tags as an attribute and vice versa. The classes:

Media = {
id: string,
Set<Tag> tags,
...
}

Tag = {
id: string,
Set<Media> medias,
...
}

The corresponding tables are:

Media
-------
id | ...

Tag
-------
id    | ...
title | ...

Media_has_tags
-------
media_id | tag_id

And now I have a set of tags with which I want to get all medias which have every tag of that set. They can have more tags of course, but they need to have every tag of the set I am providing.

Concrete example:

Media
-------
id | ...
-------
1  |
2  |

Tag
-------
id | title | ...
1  | A     |
2  | B     |

Media_has_tags
-------
media_id | tag_id
1        | 1
2        | 1
2        | 2

Given a set of tags [A, B] I want only media with id 2 as a result since media with id 1 doesn't have tag 'B'.

Can I achieve that with Keywords and if, how or do I have to build my own query?

Sorry, but your question is incorrect initially.

findAllByAttributeIn(Set<Attribute> setAttr)

produces an SQL request like this:

select * from <table_name> t where t.attribute in (?,?,?...?)

So according to RDBMS-rules your result is correct and expectable. What is a real structure for your abstract tables?

 id | attr
----------
 1  | A
 2  | A,B
 3  | A,B,C

In real life it would be somethink like this:

 id | attr
----------
 1  | A
 2  | A
 2  | B
 3  | A
 3  | B
 3  | C

And again - in this case the result you have got is ok for any RDBMS. Give us real examples from your project, please

Update because of question update :

OK, the problem has been clarified. In this case there is no straight way to solve it using standard CrudRepository syntax. But you can try to write @Query request to manage to get the goal. In a clear SQL this problem has to be solved by using group by together with having . It would be something like this:

select media_id 
From media_has_tags
Where tag_id in(1,2 3)
Group by media_id
Having count(*)=3

In terms of SpringData it means that you have to create MediaHasTagsRepository interface and an appropriate query method to get looked ids. After that you can easily find medias you're looking for. But this approach is not looking good IMHO. The best way I suppose is to find all the medias by the your initial query and than filter them by the given condition in Java. Eg you have a List<Media> where each element has an least a one tag that you are looking for. Then we can do a loop to find medias that contains all the looked tags:

List<Media> list; // here is a filled list of medias
Set<String> titles; // here is a set of title interseptions we a looking for 
final List<Media> result = new ArrayList<>();
for (Media media: list) {
  if (!list.getTags().isEmpty()){
    Set<String> tagTitles = list.getTags().stream().map(item -> item.getTitle()).filter(title -> titles.contains(title)).distinct().collect(Collectors.toSet());
    if (tagTitles.size() == titles.size()) {
      result.add(media);
    }
  }
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM