Home > Enterprise >  How can I filter a Java List based on a list attribute
How can I filter a Java List based on a list attribute

Time:01-18

hello :) I've been trying to filter a java list based on one of its attributes and its been really hard! this is my model:

@Table(name="tools_table")
public class Tools implements Serializable {

    private static final long serialVersionUID = 1L;

    @Id
    @GeneratedValue(strategy=GenerationType.IDENTITY)
    private Integer id;
    
    private String title;
    
    private String link;
    
    private String description;
    
    @ElementCollection(targetClass=String.class)
    private List<String> tags;

(theres also the getters, setters and constructors)

and I need to make a method that filters Tools that have, inside the list TAG, a certain tag. Basically, filtering tools by tag.

for example, if I have three tools ({name: one, tags:[cake, dogs, pink]},{name: two, tags:[cake, rabbits, blue]},{name: three, tags:[cake, horses, red]}) and I filter them by the tag CAKE, the three of them must come back. But if I filter them by the tag RED, only the third one should be returned.

I hope I explained it well :)

this is the method I'm trying to work with:

@GetMapping("?tag={tags}")
    public ResponseEntity<List<Tools>> findByTag(@PathVariable String tags){
        List<Tools> allTools=repo.findAll();
        allTools.stream().filter(t-> t.getTags().contains(tags)).collect(Collectors.toList());
        return ResponseEntity.ok().body(allTools);
        
}

but whenever I make the request passing the desired tag, it returns me all objects, it doesn't filter them!

I appreciate anyone who tries to help <3

CodePudding user response:

Are you sure that @GetMapping("?tag={tags}") will get the ?tag= param into the @PathVariable String tags argument? I think this will not work, you have to do plain @GetMapping and annotate the argument like @RequestParam("tag") String tags.

Moreover, as already mentioned in comments and other answers, stream() does not modify the collection it operates on - so you have to return the result of allTools.stream()...collect(Collectors.toList()).

BUT MOST IMPORTANT OF ALL (although only indirectly related to the question), what you are doing is fetch everything from the DB and filter in memory. THIS WILL KILL YOUR REAL APP, where there may be thousands of tools. Even if this specific application contains only a handful of tools, this is a bad practice and it will most certainly "bite" you in the future. Let the DB handle this operation, e.g. with a JPA query like SELECT t FROM Tools t WHERE :tag MEMBER OF t.tags.

CodePudding user response:

You are not assigning the filtered output to a new list. Below modified code would work.

@GetMapping("?tag={tags}")
public ResponseEntity<List<Tools>> findByTag(@PathVariable String tags){
    List<Tools> allTools=repo.findAll();
    List<Tools> filteredTools = allTools.stream().filter(t-> t.getTags().contains(tags)).collect(Collectors.toList());
    return ResponseEntity.ok().body(filteredTools);
    

}

  • Related